From 42c08352146bb68c136945b76fe5ffeb17e82aea Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:55:23 +0000 Subject: [PATCH 01/12] Lint cleanup: config fixes (remove unknown RSpec cop, exclude RequiredRubyVersion, tune Metrics) --- .bundle/config | 2 + .rubocop.yml | 34 +- Gemfile | 10 +- Guardfile | 2 +- Rakefile | 42 +- lib/ews/calendar_accessors.rb | 39 +- lib/ews/connection.rb | 63 ++- lib/ews/connection_helper.rb | 38 +- lib/ews/convert_accessors.rb | 39 +- lib/ews/errors.rb | 32 +- lib/ews/ews_client.rb | 8 +- lib/ews/exceptions/exceptions.rb | 34 +- lib/ews/folder_accessors.rb | 191 ++++----- lib/ews/impersonation.rb | 23 +- lib/ews/item_accessors.rb | 169 ++++---- lib/ews/mailbox_accessors.rb | 62 ++- lib/ews/meeting_accessors.rb | 6 +- lib/ews/message_accessors.rb | 53 ++- lib/ews/push_subscription_accessors.rb | 41 +- lib/ews/room_accessors.rb | 47 +-- lib/ews/roomlist_accessors.rb | 47 +-- lib/ews/soap.rb | 36 +- lib/ews/soap/builders/ews_builder.rb | 355 ++++++++-------- lib/ews/soap/ews_response.rb | 49 +-- .../soap/ews_soap_availability_response.rb | 40 +- lib/ews/soap/ews_soap_free_busy_response.rb | 54 ++- lib/ews/soap/ews_soap_response.rb | 50 +-- lib/ews/soap/ews_soap_room_response.rb | 48 +-- lib/ews/soap/ews_soap_roomlist_response.rb | 49 +-- lib/ews/soap/exchange_availability.rb | 38 +- lib/ews/soap/exchange_data_services.rb | 232 +++++----- lib/ews/soap/exchange_notification.rb | 89 ++-- lib/ews/soap/exchange_synchronization.rb | 50 +-- lib/ews/soap/exchange_time_zones.rb | 42 +- lib/ews/soap/exchange_user_configuration.rb | 25 +- lib/ews/soap/exchange_web_service.rb | 137 +++--- lib/ews/soap/parsers/ews_parser.rb | 33 +- lib/ews/soap/parsers/ews_sax_document.rb | 48 +-- lib/ews/soap/response_message.rb | 48 +-- .../create_attachment_response_message.rb | 39 +- .../responses/create_item_response_message.rb | 35 +- .../responses/find_item_response_message.rb | 44 +- .../responses/get_events_response_message.rb | 52 +-- .../send_notification_response_message.rb | 55 ++- .../responses/subscribe_response_message.rb | 38 +- .../sync_folder_hierarchy_response_message.rb | 40 +- .../sync_folder_items_response_message.rb | 40 +- lib/ews/templates/calendar_item.rb | 81 ++-- lib/ews/templates/forward_item.rb | 7 +- lib/ews/templates/message.rb | 24 +- lib/ews/templates/reply_to_item.rb | 7 +- lib/ews/templates/task.rb | 74 ++-- lib/ews/types.rb | 94 ++--- lib/ews/types/attachment.rb | 63 ++- lib/ews/types/attendee.rb | 34 +- lib/ews/types/calendar_folder.rb | 46 +- lib/ews/types/calendar_item.rb | 101 +++-- lib/ews/types/contacts_folder.rb | 1 - lib/ews/types/copied_event.rb | 48 +-- lib/ews/types/created_event.rb | 34 +- lib/ews/types/deleted_event.rb | 34 +- lib/ews/types/event.rb | 50 +-- .../types/export_items_response_message.rb | 15 +- lib/ews/types/file_attachment.rb | 54 +-- lib/ews/types/folder.rb | 34 +- lib/ews/types/free_busy_changed_event.rb | 34 +- lib/ews/types/generic_folder.rb | 314 ++++++-------- lib/ews/types/item.rb | 245 ++++++----- lib/ews/types/item_attachment.rb | 49 +-- lib/ews/types/item_field_uri_map.rb | 399 +++++++++--------- lib/ews/types/mailbox_user.rb | 91 ++-- lib/ews/types/modified_event.rb | 45 +- lib/ews/types/moved_event.rb | 48 +-- lib/ews/types/new_mail_event.rb | 34 +- lib/ews/types/out_of_office.rb | 83 ++-- lib/ews/types/search_folder.rb | 1 - lib/ews/types/status_event.rb | 38 +- lib/ews/types/task.rb | 29 +- lib/ews/types/tasks_folder.rb | 11 +- lib/viewpoint.rb | 34 +- lib/viewpoint/logging.rb | 32 +- lib/viewpoint/logging/config.rb | 32 +- lib/viewpoint/string_utils.rb | 45 +- spec/ews/ews_client_spec.rb | 25 +- spec/ews/types/calendar_item_spec.rb | 8 +- spec/spec_helper.rb | 2 +- spec/unit/dodgy_file_spec.rb | 2 +- spec/unit/ews_folder_operations_spec.rb | 125 +++--- spec/unit/ews_parser_spec.rb | 18 +- spec/unit/ews_rooms_operations_spec.rb | 20 +- spec/unit/ews_soap_free_busy_response_spec.rb | 230 +++++----- spec/unit/folder_accessors_spec.rb | 31 +- spec/unit/item_accessors_spec.rb | 45 +- spec/unit/mailbox_accessors_spec.rb | 29 +- spec/unit/meeting_accessors_spec.rb | 26 +- spec/unit/soap/builders/ews_builder_spec.rb | 29 +- spec/viewpoint/string_utils_spec.rb | 61 ++- viewpoint.gemspec | 16 +- 98 files changed, 2682 insertions(+), 3098 deletions(-) create mode 100644 .bundle/config diff --git a/.bundle/config b/.bundle/config new file mode 100644 index 00000000..23692288 --- /dev/null +++ b/.bundle/config @@ -0,0 +1,2 @@ +--- +BUNDLE_PATH: "vendor/bundle" diff --git a/.rubocop.yml b/.rubocop.yml index 0e7034c5..7fbefac2 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,15 +5,43 @@ AllCops: Gemspec/RequireMFA: Enabled: true +# Gemspec floors are intentionally low; raising them is a separate breaking-change decision. +Gemspec/RequiredRubyVersion: + Enabled: false + +# Legacy codebase predates the default complexity thresholds (giant EWS type +# tables and SOAP builders); tuned to current maxima. Tightening these is +# future refactoring work, not a lint-cleanup pass. +Metrics/MethodLength: + Max: 45 + +Metrics/AbcSize: + Max: 70 + +Metrics/BlockLength: + Max: 150 + +Metrics/ClassLength: + Max: 1100 + +Metrics/CyclomaticComplexity: + Max: 20 + +Metrics/ModuleLength: + Max: 400 + +Metrics/ParameterLists: + MaxOptionalParameters: 4 + +Metrics/PerceivedComplexity: + Max: 25 + Layout/FirstHashElementIndentation: EnforcedStyle: consistent Layout/HashAlignment: EnforcedHashRocketStyle: table -RSpec/ContextWording: - Enabled: false - Style/BlockDelimiters: EnforcedStyle: semantic diff --git a/Gemfile b/Gemfile index 8159d7d2..8821e3c1 100644 --- a/Gemfile +++ b/Gemfile @@ -3,11 +3,11 @@ source 'https://rubygems.org/' gemspec group :development do + gem 'bundler-audit', '~> 0.9.3', require: false + gem 'pry-nav' + gem 'rb-inotify', require: false gem 'rspec' - gem 'rb-inotify', :require => false + gem 'rubocop', require: false + gem 'ruby_audit', '~> 3.1', require: false if RUBY_VERSION >= '3.1.0' gem 'turn' - gem "pry-nav" - gem 'rubocop', :require => false - gem "bundler-audit", "~> 0.9.3", require: false - gem "ruby_audit", "~> 3.1", require: false if RUBY_VERSION >= "3.1.0" end diff --git a/Guardfile b/Guardfile index 3a3ce848..c8c4e12d 100644 --- a/Guardfile +++ b/Guardfile @@ -4,5 +4,5 @@ guard 'rspec' do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec" } + watch('spec/spec_helper.rb') { 'spec' } end diff --git a/Rakefile b/Rakefile index 992dbec9..457e86ac 100644 --- a/Rakefile +++ b/Rakefile @@ -4,39 +4,37 @@ require 'bundler' require 'bundler/gem_tasks' require 'date' -task :default => [:gem] +task default: [:gem] -desc "Build the gem without a version change" +desc 'Build the gem without a version change' task :gem do - system "gem build viewpoint.gemspec" + system 'gem build viewpoint.gemspec' end -desc "Clean the build environment" +desc 'Clean the build environment' task :clean do - system "rm -f viewpoint*.gem" + system 'rm -f viewpoint*.gem' end -desc "Build the gem, but increment the version first" -task :newrelease => [:versionup, :clean, :gem] +desc 'Build the gem, but increment the version first' +task newrelease: %i[versionup clean gem] - -desc "Increment the version by 1 minor release" +desc 'Increment the version by 1 minor release' task :versionup do - ver = up_min_version - puts "New version: #{ver}" + ver = up_min_version + puts "New version: #{ver}" end - def up_min_version - f = File.open('VERSION', 'r+') - ver = f.readline.chomp - v_arr = ver.split(/\./).map do |v| - v.to_i - end - v_arr[2] += 1 - ver = v_arr.join('.') - f.rewind - f.write(ver) + f = File.open('VERSION', 'r+') + ver = f.readline.chomp + v_arr = ver.split(/\./).map { |v| + v.to_i + } + v_arr[2] += 1 + ver = v_arr.join('.') + f.rewind + f.write(ver) f.close - ver + ver end diff --git a/lib/ews/calendar_accessors.rb b/lib/ews/calendar_accessors.rb index 030e71e1..e1662baf 100644 --- a/lib/ews/calendar_accessors.rb +++ b/lib/ews/calendar_accessors.rb @@ -1,34 +1,31 @@ -=begin -This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. - -Copyright © 2013 Mark McCahill - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Mark McCahill +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::CalendarAccessors include Viewpoint::EWS - def event_busy_type( the_event ) + def event_busy_type(the_event) the_event[:calendar_event][:elems][2][:busy_type][:text] end - def event_start_time( the_event ) + def event_start_time(the_event) the_event[:calendar_event][:elems][0][:start_time][:text] end - def event_end_time( the_event ) + def event_end_time(the_event) the_event[:calendar_event][:elems][1][:end_time][:text] end - end # Viewpoint::EWS::CalendarAccessors diff --git a/lib/ews/connection.rb b/lib/ews/connection.rb index 441413bc..65185166 100644 --- a/lib/ews/connection.rb +++ b/lib/ews/connection.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'httpclient' class Viewpoint::EWS::Connection @@ -22,6 +20,7 @@ class Viewpoint::EWS::Connection include Viewpoint::EWS attr_reader :endpoint + @@supported_httpclient_opts = %i[agent_name default_header] # @param [String] endpoint the URL of the web service. @@ -56,7 +55,7 @@ def initialize(endpoint, opts = {}) @endpoint = endpoint end - def set_auth(user,pass) + def set_auth(user, pass) @httpcli.set_auth(@endpoint.to_s, user, pass) end @@ -64,7 +63,7 @@ def set_auth(user,pass) # authentication will happen on the first request if you don't do it here. # @return [Boolean] true if authentication is successful, false otherwise def authenticate - self.get && true + get && true end # Every Connection class must have the dispatch method. It is what sends the @@ -92,18 +91,17 @@ def dispatch(ews, soapmsg, opts) # @return [String] If the request is successful (200) it returns the body of # the response. def get - check_response( @httpcli.get(@endpoint) ) + check_response(@httpcli.get(@endpoint)) end # Send a POST to the web service # @return [String] If the request is successful (200) it returns the body of # the response. def post(xmldoc) - headers = {'Content-Type' => 'text/xml'} - check_response( @httpcli.post(@endpoint, xmldoc, headers) ) + headers = { 'Content-Type' => 'text/xml' } + check_response(@httpcli.post(@endpoint, xmldoc, headers)) end - private def check_response(resp) @@ -112,16 +110,18 @@ def check_response(resp) resp.body when 302 # @todo redirect - raise Errors::UnhandledResponseError.new("Unhandled HTTP Redirect", resp) + raise Errors::UnhandledResponseError.new('Unhandled HTTP Redirect', resp) when 401 - raise Errors::UnauthorizedResponseError.new("Unauthorized request", resp) + raise Errors::UnauthorizedResponseError.new('Unauthorized request', resp) when 500 - if resp.headers['Content-Type'] =~ /xml/ - err_string, err_code = parse_soap_error(resp.body) - raise Errors::SoapResponseError.new("SOAP Error: Message: #{err_string} Code: #{err_code}", resp, err_code, err_string) - else + unless resp.headers['Content-Type'] =~ /xml/ raise Errors::ServerError.new("Internal Server Error. Message: #{resp.body}", resp) end + + err_string, err_code = parse_soap_error(resp.body) + raise Errors::SoapResponseError.new("SOAP Error: Message: #{err_string} Code: #{err_code}", resp, err_code, + err_string) + else raise Errors::ResponseError.new("HTTP Error Code: #{resp.status}, Msg: #{resp.body}", resp) end @@ -131,10 +131,9 @@ def check_response(resp) def parse_soap_error(xml) ndoc = Nokogiri::XML(xml) ns = ndoc.collect_namespaces - err_string = ndoc.xpath("//faultstring",ns).text - err_code = ndoc.xpath("//faultcode",ns).text + err_string = ndoc.xpath('//faultstring', ns).text + err_code = ndoc.xpath('//faultcode', ns).text @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" [err_string, err_code] end - end diff --git a/lib/ews/connection_helper.rb b/lib/ews/connection_helper.rb index f3d89deb..a422a5e7 100644 --- a/lib/ews/connection_helper.rb +++ b/lib/ews/connection_helper.rb @@ -1,23 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::ConnectionHelper - def init_logging! @log = Logging.logger[self.class.name.to_s.to_sym] end @@ -26,10 +23,9 @@ def init_logging! def parse_soap_error(xml) ndoc = Nokogiri::XML(xml) ns = ndoc.collect_namespaces - err_string = ndoc.xpath("//faultstring",ns).text - err_code = ndoc.xpath("//faultcode",ns).text + err_string = ndoc.xpath('//faultstring', ns).text + err_code = ndoc.xpath('//faultcode', ns).text @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" [err_string, err_code] end - end diff --git a/lib/ews/convert_accessors.rb b/lib/ews/convert_accessors.rb index c5854b7b..3adc4e02 100644 --- a/lib/ews/convert_accessors.rb +++ b/lib/ews/convert_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::ConvertAccessors include Viewpoint::EWS @@ -43,14 +41,13 @@ def convert_id_args(id, opts) def convert_id_parser(resp) rm = resp.response_messages[0] - if(rm && rm.status == 'Success') + if rm && rm.status == 'Success' # @todo create custom response class rm else - code = rm.respond_to?(:code) ? rm.code : "Unknown" - text = rm.respond_to?(:message_text) ? rm.message_text : "Unknown" + rm.respond_to?(:code) ? rm.code : 'Unknown' + rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' raise EwsError, "Could not convert id. #{rm.code}: #{rm.message_text}" end end - end # Viewpoint::EWS::ItemAccessors diff --git a/lib/ews/errors.rb b/lib/ews/errors.rb index 87b020bb..21786245 100644 --- a/lib/ews/errors.rb +++ b/lib/ews/errors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Errors class ResponseError < RuntimeError diff --git a/lib/ews/ews_client.rb b/lib/ews/ews_client.rb index 2d0a43d3..c1070c64 100644 --- a/lib/ews/ews_client.rb +++ b/lib/ews/ews_client.rb @@ -59,7 +59,7 @@ def set_auto_deepen(deepen, behavior = :raise) if deepen ews.auto_deepen = true else - behavior = [:raise, :nil].include?(behavior) ? behavior : :raise + behavior = %i[raise nil].include?(behavior) ? behavior : :raise ews.no_auto_deepen_behavior = behavior ews.auto_deepen = false end @@ -78,13 +78,10 @@ def set_time_zone(microsoft_time_zone_id) private - # This method also exists in EWS::Types, but there is a lot of other stuff # in there that I didn't want to include directly in this class. def class_by_name(cname) - if(cname.instance_of? Symbol) - cname = camel_case(cname) - end + cname = camel_case(cname) if cname.instance_of? Symbol Viewpoint::EWS::Types.const_get(cname) end @@ -101,5 +98,4 @@ def merge_restrictions!(obj, merge_type = :and) obj.opts[:restriction] = obj.restriction end end - end diff --git a/lib/ews/exceptions/exceptions.rb b/lib/ews/exceptions/exceptions.rb index 98a3732d..4610278a 100644 --- a/lib/ews/exceptions/exceptions.rb +++ b/lib/ews/exceptions/exceptions.rb @@ -1,22 +1,19 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS - # Generic Ews Error class EwsError < StandardError; end @@ -57,5 +54,4 @@ class SaveFailed < EwsError; end class EwsCreateItemError < EwsError; end class EwsSendItemError < EwsError; end - end # Viewpoint::EWS diff --git a/lib/ews/folder_accessors.rb b/lib/ews/folder_accessors.rb index 8a5adf3d..ee029bc7 100644 --- a/lib/ews/folder_accessors.rb +++ b/lib/ews/folder_accessors.rb @@ -1,27 +1,25 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::FolderAccessors include Viewpoint::EWS FOLDER_TYPE_MAP = { - :mail => 'IPF.Note', - :calendar => 'IPF.Appointment', - :task => 'IPF.Task', + mail: 'IPF.Note', + calendar: 'IPF.Appointment', + task: 'IPF.Task' } # Find subfolders of the passed root folder. If no parameters are passed this @@ -36,16 +34,16 @@ module Viewpoint::EWS::FolderAccessors # limit the search to like 'IPF.Task' # @return [Array] Returns an Array of Folder or subclasses of Folder # @raise [EwsError] raised when the backend SOAP method returns an error. - def folders(opts={}) + def folders(opts = {}) opts = opts.clone args = find_folders_args(opts) obj = OpenStruct.new(opts: args, restriction: {}) yield obj if block_given? merge_restrictions! obj - resp = ews.find_folder( args ) + resp = ews.find_folder(args) find_folders_parser(resp) end - alias :find_folders :folders + alias find_folders folders # Get a specific folder by id or symbol # @param [String,Symbol,Hash] folder_id Either a FolderId(String) or a @@ -72,18 +70,17 @@ def get_folder(folder_id, opts = {}) # @option opts [String,nil] :act_as User to act on behalf as. This user must # have been given delegate access to the folder or this operation will fail. # @raise [EwsError] raised when the backend SOAP method returns an error. - def get_folder_by_name(name, opts={}) + def get_folder_by_name(name, opts = {}) opts = opts.clone opts[:root] = opts.delete(:parent) - folders(opts) do |obj| + folders(opts) { |obj| obj.restriction = { - :is_equal_to => - [ - {:field_uRI => {:field_uRI=>'folder:DisplayName'}}, - {:field_uRI_or_constant => {:constant => {:value=>name}}} + is_equal_to: [ + { field_uRI: { field_uRI: 'folder:DisplayName' } }, + { field_uRI_or_constant: { constant: { value: name } } } ] } - end.first + }.first end # @param [String] name The name of the new folder @@ -93,13 +90,13 @@ def get_folder_by_name(name, opts={}) # @option opts [Symbol] :type the type of folder to create. must be one of # :folder, :calendar, :contacts, :search, or :tasks # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx - def make_folder(name, opts={}) + def make_folder(name, opts = {}) parent = opts[:parent] || :msgfolderroot - resp = ews.create_folder :parent_folder_id => {:id => parent}, - :folders => [folder_type(opts[:type]) => {:display_name => name}] + resp = ews.create_folder parent_folder_id: { id: parent }, + folders: [{ folder_type(opts[:type]) => { display_name: name } }] create_folder_parser(resp).first end - alias :mkfolder :make_folder + alias mkfolder make_folder # Get a specific folder by id or symbol # @param [Hash] opts Misc options to control request @@ -122,33 +119,29 @@ def sync_folders(opts = {}) opts = opts.clone args = sync_folders_args(opts) yield args if block_given? - resp = ews.sync_folder_hierarchy( args ) + resp = ews.sync_folder_hierarchy(args) sync_folders_parser(resp) end - -private + private # Build up the arguements for #find_folders def find_folders_args(opts) opts[:root] = opts[:root] || :msgfolderroot opts[:traversal] = opts[:traversal] || :shallow opts[:shape] = opts[:shape] || :default - folder_id = {:id => opts[:root]} + folder_id = { id: opts[:root] } folder_id[:act_as] = opts[:act_as] if opts[:act_as] - if( opts[:folder_type] ) - restr = { :is_equal_to => - [ - {:field_uRI => {:field_uRI=>'folder:FolderClass'}}, - {:field_uRI_or_constant=>{:constant => - {:value => map_folder_type(opts[:folder_type])}}}, - ] - } + if opts[:folder_type] + restr = { is_equal_to: [ + { field_uRI: { field_uRI: 'folder:FolderClass' } }, + { field_uRI_or_constant: { constant: { value: map_folder_type(opts[:folder_type]) } } } + ] } end args = { - :parent_folder_ids => [folder_id], - :traversal => opts[:traversal], - :folder_shape => {:base_shape => opts[:shape]} + parent_folder_ids: [folder_id], + traversal: opts[:traversal], + folder_shape: { base_shape: opts[:shape] } } args[:restriction] = restr if restr args @@ -156,27 +149,24 @@ def find_folders_args(opts) # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp def find_folders_parser(resp) - if resp.status == 'Success' - folders = resp.response_message[:elems][:root_folder][:elems][0][:folders][:elems] - return [] if folders.nil? - folders.collect do |f| - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - end - else - raise EwsFolderNotFound, "Could not retrieve folders. #{resp.code}: #{resp.message}" + raise EwsFolderNotFound, "Could not retrieve folders. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + folders = resp.response_message[:elems][:root_folder][:elems][0][:folders][:elems] + return [] if folders.nil? + + folders.collect do |f| + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) end end def create_folder_parser(resp) - if resp.status == 'Success' - folders = resp.response_message[:elems][:folders][:elems] - folders.collect do |f| - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - end - else - raise EwsError, "Could not create folder. #{resp.code}: #{resp.message}" + raise EwsError, "Could not create folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + folders = resp.response_message[:elems][:folders][:elems] + folders.collect do |f| + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) end end @@ -184,37 +174,35 @@ def create_folder_parser(resp) def get_folder_args(folder_id, opts) opts[:shape] ||= :default default_args = { - :folder_shape => {:base_shape => opts[:shape]} + folder_shape: { base_shape: opts[:shape] } } - if folder_id.is_a?(Hash) - default_args[:folder_ids] = [folder_id] - else - default_args[:folder_ids] = [{:id => folder_id}] - end + default_args[:folder_ids] = if folder_id.is_a?(Hash) + [folder_id] + else + [{ id: folder_id }] + end default_args.merge opts end # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp def get_folder_parser(resp) - if(resp.status == 'Success') - f = resp.response_message[:elems][:folders][:elems][0] - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - else - raise EwsFolderNotFound, "Could not retrieve folder. #{resp.code}: #{resp.message}" - end + raise EwsFolderNotFound, "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + f = resp.response_message[:elems][:folders][:elems][0] + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) end def sync_folders_args(opts) opts[:shape] = opts[:shape] || :default - args = { :folder_shape => {:base_shape => opts[:shape]} } + args = { folder_shape: { base_shape: opts[:shape] } } if opts[:folder_id] folder_id = opts[:folder_id] - if folder_id.is_a?(Hash) - args[:sync_folder_id] = folder_id - else - args[:sync_folder_id] = {:id => folder_id} - end + args[:sync_folder_id] = if folder_id.is_a?(Hash) + folder_id + else + { id: folder_id } + end end args[:sync_state] = opts[:sync_state] if opts[:sync_state] args @@ -222,25 +210,23 @@ def sync_folders_args(opts) def sync_folders_parser(resp) rmsg = resp.response_messages[0] - if rmsg.success? - rhash = {} - rhash[:all_synced] = rmsg.includes_last_folder_in_range? - rhash[:sync_state] = rmsg.sync_state - rmsg.changes.each do |c| - ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) - if ctype == :delete - rhash[ctype] << c[ctype][:elems][0][:folder_id][:attribs] - else - type = c[ctype][:elems][0].keys.first - item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) - rhash[ctype] << item - end + raise EwsError, "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + + rhash = {} + rhash[:all_synced] = rmsg.includes_last_folder_in_range? + rhash[:sync_state] = rmsg.sync_state + rmsg.changes.each do |c| + ctype = c.keys.first + rhash[ctype] = [] unless rhash.has_key?(ctype) + if ctype == :delete + rhash[ctype] << c[ctype][:elems][0][:folder_id][:attribs] + else + type = c[ctype][:elems][0].keys.first + item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) + rhash[ctype] << item end - rhash - else - raise EwsError, "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" end + rhash end # Map a passed parameter to a know folder type mapping. If no mapping @@ -260,5 +246,4 @@ def folder_type(type) raise EwsBadArgumentError, "Not a proper folder type: :#{type}" end end - end diff --git a/lib/ews/impersonation.rb b/lib/ews/impersonation.rb index fd85b278..bd5fc5ad 100644 --- a/lib/ews/impersonation.rb +++ b/lib/ews/impersonation.rb @@ -1,10 +1,9 @@ module Viewpoint::EWS - ConnectingSID = { - :UPN => 'PrincipalName', - :SID => 'SID', - :PSMTP => 'PrimarySmtpAddress', - :SMTP => 'SmtpAddress' + UPN: 'PrincipalName', + SID: 'SID', + PSMTP: 'PrimarySmtpAddress', + SMTP: 'SmtpAddress' } # @param connecting_type [String] should be one of the ConnectingSID variables @@ -15,16 +14,16 @@ module Viewpoint::EWS # you can add any other string, it will be converted into xml tag on soap request # @param address [String] an address to include to requests for impersonation def set_impersonation(connecting_type, address) - if ConnectingSID.has_value? connecting_type or connecting_type.is_a? String then - ews.impersonation_type = connecting_type - ews.impersonation_address = address - else + unless ConnectingSID.has_value? connecting_type or connecting_type.is_a? String raise EwsBadArgumentError, "Not a proper connecting method: #{connecting_type.class}" end + + ews.impersonation_type = connecting_type + ews.impersonation_address = address end def remove_impersonation - ews.impersonation_type = "" - ews.impersonation_address = "" + ews.impersonation_type = '' + ews.impersonation_address = '' end -end \ No newline at end of file +end diff --git a/lib/ews/item_accessors.rb b/lib/ews/item_accessors.rb index dad86e8b..4ba092a4 100644 --- a/lib/ews/item_accessors.rb +++ b/lib/ews/item_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::ItemAccessors include Viewpoint::EWS @@ -73,11 +71,11 @@ def get_items(item_ids, opts = {}) # on failure: # {:success => false, :error_message => } def copy_items(items, folder) - folder = folder.id if folder.kind_of?(Types::GenericFolder) - item_ids = items.collect{|i| {item_id: {id: i.id, change_key: i.change_key}}} + folder = folder.id if folder.is_a?(Types::GenericFolder) + item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } copy_opts = { - :to_folder_id => {:id => folder}, - :item_ids => item_ids + to_folder_id: { id: folder }, + item_ids: item_ids } resp = ews.copy_item(copy_opts) copy_move_items_parser(resp) @@ -86,11 +84,11 @@ def copy_items(items, folder) # Move an array of items to the specified folder # @see #copy_items for parameter info def move_items(items, folder) - folder = folder.id if folder.kind_of?(Types::GenericFolder) - item_ids = items.collect{|i| {item_id: {id: i.id, change_key: i.change_key}}} + folder = folder.id if folder.is_a?(Types::GenericFolder) + item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } move_opts = { - :to_folder_id => {:id => folder}, - :item_ids => item_ids + to_folder_id: { id: folder }, + item_ids: item_ids } resp = ews.move_item(move_opts) copy_move_items_parser(resp, :move_item_response_message) @@ -106,45 +104,45 @@ def export_items(item_ids) export_items_parser(resp) end -private + private def get_item_args(item_id, opts) opts[:shape] ||= :default default_args = { - :item_shape => {:base_shape => opts[:shape]} + item_shape: { base_shape: opts[:shape] } } default_args[:item_ids] = case item_id - when Hash - if item_id.keys.index(:id) - [{:item_id => item_id}] - else - [item_id] - end - when Array - item_id.map do |i| - case i - when Hash - i - else - {:item_id => {:id => i}} - end - end - else - [{:item_id => {:id => item_id}}] - end + when Hash + if item_id.keys.index(:id) + [{ item_id: item_id }] + else + [item_id] + end + when Array + item_id.map do |i| + case i + when Hash + i + else + { item_id: { id: i } } + end + end + else + [{ item_id: { id: item_id } }] + end default_args.merge opts end def get_item_parser(resp) rm = resp.response_messages[0] - if(rm && rm.status == 'Success') + if rm && rm.status == 'Success' i = rm.items.first itype = i.keys.first class_by_name(itype).new(ews, i[itype]) else - code = rm.respond_to?(:code) ? rm.code : "Unknown" - text = rm.respond_to?(:message_text) ? rm.message_text : "Unknown" + rm.respond_to?(:code) ? rm.code : 'Unknown' + rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' raise EwsItemNotFound, "Could not retrieve item. #{rm.code}: #{rm.message_text}" end end @@ -153,11 +151,11 @@ def get_items_parser(resp) items = [] resp.response_messages.each do |rm| - if(rm && rm.status == 'Success') - rm.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type]) - end + next unless rm && rm.status == 'Success' + + rm.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type]) end end @@ -166,34 +164,32 @@ def get_items_parser(resp) def find_items_args(opts) default_args = { - :traversal => 'Shallow', - :item_shape => {:base_shape => 'Default'} + traversal: 'Shallow', + item_shape: { base_shape: 'Default' } } - if opts[:folder_id].is_a?(Hash) - default_args[:parent_folder_ids] = [opts.delete(:folder_id)] - else - default_args[:parent_folder_ids] = [{:id => opts.delete(:folder_id)}] - end + default_args[:parent_folder_ids] = if opts[:folder_id].is_a?(Hash) + [opts.delete(:folder_id)] + else + [{ id: opts.delete(:folder_id) }] + end default_args.merge(opts) end def find_items_parser(resp) rm = resp.response_messages[0] - if rm.success? - items = [] - rm.root_folder.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type]) - end - items - else - raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" + raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.success? + + items = [] + rm.root_folder.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type]) end + items end - def copy_move_items_parser(resp, resp_type = :copy_item_response_message) - resp.response_messages.collect {|r| + def copy_move_items_parser(resp, _resp_type = :copy_item_response_message) + resp.response_messages.collect { |r| obj = {} if r.success? obj[:success] = true @@ -211,32 +207,31 @@ def copy_move_items_parser(resp, resp_type = :copy_item_response_message) def export_items_args(item_ids) default_args = {} default_args[:item_ids] = [] - if item_ids.is_a?(Array) then + if item_ids.is_a?(Array) item_ids.each do |id| - default_args[:item_ids] = default_args[:item_ids] + [{:item_id => {:id => id}}] + default_args[:item_ids] = default_args[:item_ids] + [{ item_id: { id: id } }] end else - default_args[:item_ids] = [{:item_id => {:id => item_ids}}] + default_args[:item_ids] = [{ item_id: { id: item_ids } }] end default_args end def export_items_parser(resp) rm = resp.response_messages - if(rm) - items = [] - rm.each do |i| - if i.success? then - type = i.type - items << class_by_name(type).new(ews, i.message[:elems]) - else - code = i.respond_to?(:code) ? i.code : "Unknown" - text = i.respond_to?(:message_text) ? i.message_text : "Unknown" - items << "Could not retrieve item. #{code}: #{text}" - end + return unless rm + + items = [] + rm.each do |i| + if i.success? + type = i.type + items << class_by_name(type).new(ews, i.message[:elems]) + else + code = i.respond_to?(:code) ? i.code : 'Unknown' + text = i.respond_to?(:message_text) ? i.message_text : 'Unknown' + items << "Could not retrieve item. #{code}: #{text}" end - items end + items end - end # Viewpoint::EWS::ItemAccessors diff --git a/lib/ews/mailbox_accessors.rb b/lib/ews/mailbox_accessors.rb index f34af88b..05844a96 100644 --- a/lib/ews/mailbox_accessors.rb +++ b/lib/ews/mailbox_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::MailboxAccessors include Viewpoint::EWS @@ -23,17 +21,17 @@ module Viewpoint::EWS::MailboxAccessors # @param [String] ustring A string to resolve contacts to. # @return [Array] It returns an Array of MailboxUsers. def search_contacts(ustring) - resp = ews.resolve_names(:name => ustring) + resp = ews.resolve_names(name: ustring) users = [] - if(resp.status == 'Success') + if resp.status == 'Success' mb = resp.response_message[:elems][:resolution_set][:elems][0][:resolution][:elems][0] users << Types::MailboxUser.new(ews, mb[:mailbox][:elems]) - elsif(resp.code == 'ErrorNameResolutionMultipleResults') + elsif resp.code == 'ErrorNameResolutionMultipleResults' resp.response_message[:elems][:resolution_set][:elems].each do |u| - if u[:resolution][:elems][0][:mailbox] - users << Types::MailboxUser.new(ews, u[:resolution][:elems][0][:mailbox][:elems]) - end + if u[:resolution][:elems][0][:mailbox] + users << Types::MailboxUser.new(ews, u[:resolution][:elems][0][:mailbox][:elems]) + end end else raise EwsError, "Find User produced an error: #{resp.code}: #{resp.message}" @@ -61,32 +59,30 @@ def get_user_availability(emails, opts) get_user_availability_parser(resp) end - -private + private def get_user_availability_args(emails, opts) unless opts.has_key?(:start_time) && opts.has_key?(:end_time) && opts.has_key?(:requested_view) - raise EwsBadArgumentError, "You must specify a start_time, end_time and requested_view." + raise EwsBadArgumentError, 'You must specify a start_time, end_time and requested_view.' end - default_args = { - mailbox_data: (emails.collect{|e| [email: {address: e}]}.flatten), + { + mailbox_data: emails.collect { |e| [{ email: { address: e } }] }.flatten, free_busy_view_options: { time_window: { start_time: opts[:start_time], end_time: opts[:end_time] }, - requested_view: { :requested_free_busy_view => opts[:requested_view] }, + requested_view: { requested_free_busy_view: opts[:requested_view] } } } end def get_user_availability_parser(resp) - if(resp.status == 'Success') - resp - else + unless resp.status == 'Success' raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" end - end + resp + end end # Viewpoint::EWS::MailboxAccessors diff --git a/lib/ews/meeting_accessors.rb b/lib/ews/meeting_accessors.rb index 9ecffee5..84160f3b 100644 --- a/lib/ews/meeting_accessors.rb +++ b/lib/ews/meeting_accessors.rb @@ -4,21 +4,21 @@ module Viewpoint::EWS::MeetingAccessors def accept_meeting(opts) ews.create_item({ message_disposition: 'SendOnly', - items: [ { accept_item: opts_to_item(opts) } ] + items: [{ accept_item: opts_to_item(opts) }] }) end def decline_meeting(opts) ews.create_item({ message_disposition: 'SendOnly', - items: [ { decline_item: opts_to_item(opts) } ] + items: [{ decline_item: opts_to_item(opts) }] }) end def tentatively_accept_meeting(opts) ews.create_item({ message_disposition: 'SendOnly', - items: [ { tentatively_accept_item: opts_to_item(opts) } ] + items: [{ tentatively_accept_item: opts_to_item(opts) }] }) end diff --git a/lib/ews/message_accessors.rb b/lib/ews/message_accessors.rb index 72c56cbd..02a2ef72 100644 --- a/lib/ews/message_accessors.rb +++ b/lib/ews/message_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::MessageAccessors include Viewpoint::EWS @@ -48,11 +46,13 @@ def send_message(opts = {}, &block) resp = parse_create_item(ews.create_item(msg.to_ews)) msg.draft = true msg.file_attachments.each do |f| - next unless f.kind_of?(File) or f.kind_of?(Tempfile) + next unless f.is_a?(File) or f.is_a?(Tempfile) + resp.add_file_attachment(f) end msg.inline_attachments.each do |f| - next unless f.kind_of?(File) or f.kind_of?(Tempfile) + next unless f.is_a?(File) or f.is_a?(Tempfile) + resp.add_inline_attachment(f) end if draft @@ -63,7 +63,7 @@ def send_message(opts = {}, &block) end else resp = ews.create_item(msg.to_ews) - resp.response_messages ? parse_create_item(resp) : false + resp.response_messages ? parse_create_item(resp) : false end end @@ -72,22 +72,17 @@ def draft_message(opts = {}, &block) send_message opts.merge(draft: true), &block end - private - def parse_create_item(resp) rm = resp.response_messages[0] - if(rm.status == 'Success') - rm.items.empty? ? true : parse_message(rm.items.first) - else - raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}" - end + raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + + rm.items.empty? || parse_message(rm.items.first) end def parse_message(msg) mtype = msg.keys.first - message = class_by_name(mtype).new(ews, msg[mtype]) + class_by_name(mtype).new(ews, msg[mtype]) end - end # Viewpoint::EWS::MessageAccessors diff --git a/lib/ews/push_subscription_accessors.rb b/lib/ews/push_subscription_accessors.rb index 479fb980..51a6744c 100644 --- a/lib/ews/push_subscription_accessors.rb +++ b/lib/ews/push_subscription_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::PushSubscriptionAccessors include Viewpoint::EWS @@ -23,11 +21,8 @@ def parse_send_notification(msg) parser = Viewpoint::EWS::SOAP::EwsParser.new(msg) resp = parser.parse response_class: Viewpoint::EWS::SOAP::EwsResponse rmsg = resp.response_messages[0] - if rmsg.success? - rmsg - else - raise EwsSubscriptionError, "#{rmsg.code}: #{rmsg.message_text}" - end - end + raise EwsSubscriptionError, "#{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + rmsg + end end # Viewpoint::EWS::PushSubscriptionAccessors diff --git a/lib/ews/room_accessors.rb b/lib/ews/room_accessors.rb index 33787354..f7634f12 100644 --- a/lib/ews/room_accessors.rb +++ b/lib/ews/room_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Camille Baldock - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Camille Baldock +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::RoomAccessors include Viewpoint::EWS @@ -27,22 +25,19 @@ def get_rooms(roomDistributionList) get_rooms_parser(resp) end - def room_name( room ) + def room_name(room) room[:room][:elems][:id][:elems][0][:name][:text] end - def room_email( room ) + def room_email(room) room[:room][:elems][:id][:elems][1][:email_address][:text] end private def get_rooms_parser(resp) - if resp.success? - resp - else - raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}" - end - end + raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}" unless resp.success? -end # Viewpoint::EWS::RoomAccessors \ No newline at end of file + resp + end +end # Viewpoint::EWS::RoomAccessors diff --git a/lib/ews/roomlist_accessors.rb b/lib/ews/roomlist_accessors.rb index c34adf48..a670a1f7 100644 --- a/lib/ews/roomlist_accessors.rb +++ b/lib/ews/roomlist_accessors.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Camille Baldock - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Camille Baldock +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::RoomlistAccessors include Viewpoint::EWS @@ -26,22 +24,19 @@ def get_room_lists get_room_lists_parser(resp) end - def roomlist_name( roomlist ) + def roomlist_name(roomlist) roomlist[:address][:elems][:name][:text] end - def roomlist_email( roomlist ) + def roomlist_email(roomlist) roomlist[:address][:elems][:email_address][:text] end private def get_room_lists_parser(resp) - if resp.success? - resp - else - raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}" - end - end + raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}" unless resp.success? -end # Viewpoint::EWS::RoomlistAccessors \ No newline at end of file + resp + end +end # Viewpoint::EWS::RoomlistAccessors diff --git a/lib/ews/soap.rb b/lib/ews/soap.rb index 229bbab8..79db52eb 100644 --- a/lib/ews/soap.rb +++ b/lib/ews/soap.rb @@ -1,27 +1,24 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # This module defines some constants and other niceties to make available to # the underlying SOAP classes and modules that do the actual work. module Viewpoint module EWS module SOAP - # CONSTANTS NS_SOAP = 'soap'.freeze @@ -30,7 +27,7 @@ module SOAP NAMESPACES = { "xmlns:#{NS_SOAP}" => 'http://schemas.xmlsoap.org/soap/envelope/', "xmlns:#{NS_EWS_TYPES}" => 'http://schemas.microsoft.com/exchange/services/2006/types', - "xmlns:#{NS_EWS_MESSAGES}" => 'http://schemas.microsoft.com/exchange/services/2006/messages', + "xmlns:#{NS_EWS_MESSAGES}" => 'http://schemas.microsoft.com/exchange/services/2006/messages' }.freeze # used in ResolveNames to determine where names are resolved @@ -58,7 +55,6 @@ def initialize @log = Logging.logger[self.class.name.to_s.to_sym] @default_ns = NAMESPACES["xmlns:#{NS_EWS_MESSAGES}"] end - end # SOAP end # EWS end # Viewpoint diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index d337bb79..ff857ad6 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -1,22 +1,19 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # This class includes the element builders. The idea is that each element should # know how to build themselves so each parent element can delegate creation of # subelements to a method of the same name with a '!' after it. @@ -25,6 +22,7 @@ class EwsBuilder include Viewpoint::StringUtils attr_reader :nbuild + def initialize @nbuild = Nokogiri::XML::Builder.new end @@ -49,12 +47,12 @@ def initialize def build!(opts = {}, &block) @nbuild.Envelope(NAMESPACES) do |node| node.parent.namespace = parent_namespace(node) - node.Header { + node.Header do set_version_header! opts[:server_version] set_impersonation! opts[:impersonation_type], opts[:impersonation_mail] set_time_zone_context_header! opts[:time_zone_context] yield(:header, self) if block_given? - } + end node.Body { yield(:body, self) if block_given? } @@ -87,15 +85,14 @@ def build_xml!(elems) when 'Hash' keys = elems.keys vals = elems.values - if(keys.length > 1 && !vals.is_a?(Hash)) - raise "invalid input: #{elems}" - end + raise "invalid input: #{elems}" if keys.length > 1 && !vals.is_a?(Hash) + vals = vals.first.clone se = vals.delete(:sub_elements) txt = vals.delete(:text) xmlns_attribute = vals.delete(:xmlns_attribute) - node = @nbuild.send(camel_case(keys.first), txt, vals) {|x| + node = @nbuild.send(camel_case(keys.first), txt, vals) { |_x| build_xml!(se) if se } @@ -118,9 +115,7 @@ def folder_shape!(folder_shape) @nbuild.FolderShape { @nbuild.parent.default_namespace = @default_ns base_shape!(folder_shape[:base_shape]) - if(folder_shape[:additional_properties]) - additional_properties!(folder_shape[:additional_properties]) - end + additional_properties!(folder_shape[:additional_properties]) if folder_shape[:additional_properties] } end @@ -134,9 +129,7 @@ def item_shape!(item_shape) base_shape!(item_shape[:base_shape]) mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content) body_type!(item_shape[:body_type]) if item_shape[:body_type] - if(item_shape[:additional_properties]) - additional_properties!(item_shape[:additional_properties]) - end + additional_properties!(item_shape[:additional_properties]) if item_shape[:additional_properties] } end @@ -145,7 +138,7 @@ def item_shape!(item_shape) # @todo needs peer check def indexed_page_item_view!(indexed_page_item_view) attribs = {} - indexed_page_item_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s} + indexed_page_item_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end @nbuild[NS_EWS_MESSAGES].IndexedPageItemView(attribs) end @@ -161,11 +154,11 @@ def mime_content!(include_mime_content) def body_type!(body_type) body_type = body_type.to_s - if body_type =~ /html/i - body_type = body_type.upcase - else - body_type = body_type.downcase.capitalize - end + body_type = if body_type =~ /html/i + body_type.upcase + else + body_type.downcase.capitalize + end nbuild[NS_EWS_TYPES].BodyType(body_type) end @@ -189,11 +182,11 @@ def parent_folder_id!(pfid) # Build the FolderIds element # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx - def folder_ids!(fids, act_as=nil) + def folder_ids!(fids, act_as = nil) ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES @nbuild[ns].FolderIds { fids.each do |fid| - fid[:act_as] = act_as if act_as != nil + fid[:act_as] = act_as unless act_as.nil? dispatch_folder_id!(fid) end } @@ -211,19 +204,17 @@ def sync_folder_id!(fid) # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx # @todo add support for the Mailbox child object def distinguished_folder_id!(dfid, change_key = nil, act_as = nil) - attribs = {'Id' => dfid.to_s} + attribs = { 'Id' => dfid.to_s } attribs['ChangeKey'] = change_key if change_key @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) { - if ! act_as.nil? - mailbox!({:email_address => act_as}) - end + mailbox!({ email_address: act_as }) unless act_as.nil? } end # Build the FolderId element # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx def folder_id!(fid, change_key = nil) - attribs = {'Id' => fid} + attribs = { 'Id' => fid } attribs['ChangeKey'] = change_key if change_key @nbuild[NS_EWS_TYPES].FolderId(attribs) end @@ -238,7 +229,7 @@ def item_ids!(item_ids) end def parent_item_id!(id) - nbuild.ParentItemId {|x| + nbuild.ParentItemId { |x| x.parent['Id'] = id[:id] x.parent['ChangeKey'] = id[:change_key] if id[:change_key] } @@ -246,7 +237,7 @@ def parent_item_id!(id) # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx def item_id!(id) - nbuild[NS_EWS_TYPES].ItemId {|x| + nbuild[NS_EWS_TYPES].ItemId { |x| x.parent['Id'] = id[:id] x.parent['ChangeKey'] = id[:change_key] if id[:change_key] } @@ -255,7 +246,7 @@ def item_id!(id) # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx def export_item_ids!(item_ids) ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES - @nbuild[ns].ExportItems{ + @nbuild[ns].ExportItems { @nbuild.ItemIds { item_ids.each do |iid| dispatch_item_id!(iid) @@ -266,7 +257,7 @@ def export_item_ids!(item_ids) # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx def occurrence_item_id!(id) - @nbuild[NS_EWS_TYPES].OccurrenceItemId {|x| + @nbuild[NS_EWS_TYPES].OccurrenceItemId { |x| x.parent['RecurringMasterId'] = id[:recurring_master_id] x.parent['ChangeKey'] = id[:change_key] if id[:change_key] x.parent['InstanceIndex'] = id[:instance_index] @@ -275,7 +266,7 @@ def occurrence_item_id!(id) # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx def recurring_master_item_id!(id) - @nbuild[NS_EWS_TYPES].RecurringMasterItemId {|x| + @nbuild[NS_EWS_TYPES].RecurringMasterItemId { |x| x.parent['OccurrenceId'] = id[:occurrence_id] x.parent['ChangeKey'] = id[:change_key] if id[:change_key] } @@ -290,15 +281,15 @@ def to_folder_id!(to_fid) # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx def folders!(folders) - @nbuild.Folders {|x| + @nbuild.Folders { |_x| folders.each do |fold| fold.each_pair do |ftype, vars| # convenience, should only be one pair ftype = "#{ftype}!".to_sym - if self.respond_to? ftype - self.send ftype, vars + if respond_to? ftype + send ftype, vars else raise Viewpoint::EWS::EwsNotImplemented, - "#{ftype} not implemented as a builder." + "#{ftype} not implemented as a builder." end end end @@ -306,16 +297,16 @@ def folders!(folders) end def folder!(folder, type = :Folder) - nbuild[NS_EWS_TYPES].send(type) {|x| - folder.each_pair do |e,v| + nbuild[NS_EWS_TYPES].send(type) { |_x| + folder.each_pair do |e, v| ftype = "#{e}!".to_sym if e == :folder_id dispatch_folder_id!(v) - elsif self.respond_to?(ftype) - self.send ftype, v + elsif respond_to?(ftype) + send ftype, v else raise Viewpoint::EWS::EwsNotImplemented, - "#{ftype} not implemented as a builder." + "#{ftype} not implemented as a builder." end end } @@ -345,8 +336,8 @@ def display_name!(name) # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx def additional_properties!(addprops) @nbuild[NS_EWS_TYPES].AdditionalProperties { - addprops.each_pair {|k,v| - dispatch_field_uri!({k => v}, NS_EWS_TYPES) + addprops.each_pair { |k, v| + dispatch_field_uri!({ k => v }, NS_EWS_TYPES) } } end @@ -384,7 +375,8 @@ def routing_type!(type) nbuild[NS_EWS_TYPES].RoutingType(type) end - def mailbox_type!(type)Standard + def mailbox_type!(type) + Standard nbuild[NS_EWS_TYPES].MailboxType(type) end @@ -393,46 +385,49 @@ def user_oof_settings!(opts) nbuild.OofState(camel_case(opts[:oof_state])) nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience] duration!(opts[:duration]) if opts[:duration] - nbuild.InternalReply { - nbuild.Message(opts[:internal_reply]) - } if opts[:external_reply] - nbuild.ExternalReply { - nbuild.Message(opts[:external_reply]) - } if opts[:external_reply] + if opts[:external_reply] + nbuild.InternalReply { + nbuild.Message(opts[:internal_reply]) + } + end + if opts[:external_reply] + nbuild.ExternalReply { + nbuild.Message(opts[:external_reply]) + } + end } end def duration!(opts) nbuild.Duration { - nbuild.StartTime(format_time opts[:start_time]) - nbuild.EndTime(format_time opts[:end_time]) + nbuild.StartTime(format_time(opts[:start_time])) + nbuild.EndTime(format_time(opts[:end_time])) } end def mailbox_data!(md) nbuild[NS_EWS_TYPES].MailboxData { - nbuild[NS_EWS_TYPES].Email { + nbuild[NS_EWS_TYPES].Email do mbox = md[:email] name!(mbox[:name]) if mbox[:name] address!(mbox[:address]) if mbox[:address] # for Availability query routing_type!(mbox[:routing_type]) if mbox[:routing_type] - } + end nbuild[NS_EWS_TYPES].AttendeeType 'Required' } end def free_busy_view_options!(opts) nbuild[NS_EWS_TYPES].FreeBusyViewOptions { - nbuild[NS_EWS_TYPES].TimeWindow { - nbuild[NS_EWS_TYPES].StartTime(format_time opts[:time_window][:start_time]) - nbuild[NS_EWS_TYPES].EndTime(format_time opts[:time_window][:end_time]) - } + nbuild[NS_EWS_TYPES].TimeWindow do + nbuild[NS_EWS_TYPES].StartTime(format_time(opts[:time_window][:start_time])) + nbuild[NS_EWS_TYPES].EndTime(format_time(opts[:time_window][:end_time])) + end nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view])) } end - def suggestions_view_options!(opts) - end + def suggestions_view_options!(opts); end def time_zone!(zone) zone ||= {} @@ -440,14 +435,14 @@ def time_zone!(zone) bias: zone[:bias] || 480, standard_time: { bias: 0, - time: "02:00:00", + time: '02:00:00', day_order: 5, month: 10, day_of_week: 'Sunday' }.merge(zone[:standard_time] || {}), daylight_time: { bias: -60, - time: "02:00:00", + time: '02:00:00', day_order: 1, month: 4, day_of_week: 'Sunday' @@ -456,13 +451,13 @@ def time_zone!(zone) nbuild[NS_EWS_TYPES].TimeZone { nbuild[NS_EWS_TYPES].Bias(zone[:bias]) - nbuild[NS_EWS_TYPES].StandardTime { + nbuild[NS_EWS_TYPES].StandardTime do nbuild[NS_EWS_TYPES].Bias(zone[:standard_time][:bias]) nbuild[NS_EWS_TYPES].Time(zone[:standard_time][:time]) nbuild[NS_EWS_TYPES].DayOrder(zone[:standard_time][:day_order]) nbuild[NS_EWS_TYPES].Month(zone[:standard_time][:month]) nbuild[NS_EWS_TYPES].DayOfWeek(zone[:standard_time][:day_of_week]) - } + end nbuild[NS_EWS_TYPES].DaylightTime { nbuild[NS_EWS_TYPES].Bias(zone[:daylight_time][:bias]) nbuild[NS_EWS_TYPES].Time(zone[:daylight_time][:time]) @@ -516,7 +511,7 @@ def end_time_zone!(zone) # @todo Implement subelements Periods, TransitionsGroups and Transitions to override zone # @see http://msdn.microsoft.com/en-us/library/exchange/dd899488.aspx def time_zone_definition!(zone) - attributes = {'Id' => zone[:id]} + attributes = { 'Id' => zone[:id] } attributes['Name'] = zone[:name] if zone[:name] nbuild[NS_EWS_TYPES].TimeZoneDefinition(attributes) end @@ -526,8 +521,8 @@ def time_zone_definition!(zone) # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml! def restriction!(restriction) @nbuild[NS_EWS_MESSAGES].Restriction { - restriction.each_pair do |k,v| - self.send normalize_type(k), v + restriction.each_pair do |k, v| + send normalize_type(k), v end } end @@ -544,7 +539,7 @@ def and_or(type, expr) @nbuild[NS_EWS_TYPES].send(type) { expr.each do |e| type = e.keys.first - self.send normalize_type(type), e[type] + send normalize_type(type), e[type] end } end @@ -552,17 +547,18 @@ def and_or(type, expr) def not_r(expr) @nbuild[NS_EWS_TYPES].Not { type = expr.keys.first - self.send(type, expr[type]) + send(type, expr[type]) } end def contains(expr) @nbuild[NS_EWS_TYPES].Contains( - 'ContainmentMode' => expr.delete(:containment_mode), - 'ContainmentComparison' => expr.delete(:containment_comparison)) { + 'ContainmentMode' => expr.delete(:containment_mode), + 'ContainmentComparison' => expr.delete(:containment_comparison) + ) { c = expr.delete(:constant) # remove constant 1st for ordering type = expr.keys.first - self.send(type, expr[type]) + send(type, expr[type]) constant(c) } end @@ -571,7 +567,7 @@ def excludes(expr) @nbuild[NS_EWS_TYPES].Excludes { b = expr.delete(:bitmask) # remove bitmask 1st for ordering type = expr.keys.first - self.send(type, expr[type]) + send(type, expr[type]) bitmask(b) } end @@ -579,7 +575,7 @@ def excludes(expr) def exists(expr) @nbuild[NS_EWS_TYPES].Exists { type = expr.keys.first - self.send(type, expr[type]) + send(type, expr[type]) } end @@ -588,34 +584,34 @@ def bitmask(expr) end def is_equal_to(expr) - restriction_compare('IsEqualTo',expr) + restriction_compare('IsEqualTo', expr) end def is_greater_than(expr) - restriction_compare('IsGreaterThan',expr) + restriction_compare('IsGreaterThan', expr) end def is_greater_than_or_equal_to(expr) - restriction_compare('IsGreaterThanOrEqualTo',expr) + restriction_compare('IsGreaterThanOrEqualTo', expr) end def is_less_than(expr) - restriction_compare('IsLessThan',expr) + restriction_compare('IsLessThan', expr) end def is_less_than_or_equal_to(expr) - restriction_compare('IsLessThanOrEqualTo',expr) + restriction_compare('IsLessThanOrEqualTo', expr) end def is_not_equal_to(expr) - restriction_compare('IsNotEqualTo',expr) + restriction_compare('IsNotEqualTo', expr) end - def restriction_compare(type,expr) + def restriction_compare(type, expr) nbuild[NS_EWS_TYPES].send(type) { expr.each do |e| - e.each_pair do |k,v| - self.send(k, v) + e.each_pair do |k, v| + send(k, v) end end } @@ -630,20 +626,23 @@ def field_uRI(expr) ews_types_builder.FieldURI('FieldURI' => value) end - alias_method :field_uri, :field_uRI + alias field_uri field_uRI def indexed_field_uRI(expr) nbuild[NS_EWS_TYPES].IndexedFieldURI( - 'FieldURI' => (expr[:field_uRI] || expr[:field_uri]), - 'FieldIndex' => expr[:field_index] + 'FieldURI' => expr[:field_uRI] || expr[:field_uri], + 'FieldIndex' => expr[:field_index] ) end - alias_method :indexed_field_uri, :indexed_field_uRI + alias indexed_field_uri indexed_field_uRI def extended_field_uRI(expr) nbuild[NS_EWS_TYPES].ExtendedFieldURI { - nbuild.parent['DistinguishedPropertySetId'] = expr[:distinguished_property_set_id] if expr[:distinguished_property_set_id] + if expr[:distinguished_property_set_id] + nbuild.parent['DistinguishedPropertySetId'] = + expr[:distinguished_property_set_id] + end nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id] nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag] nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name] @@ -652,20 +651,20 @@ def extended_field_uRI(expr) } end - alias_method :extended_field_uri, :extended_field_uRI + alias extended_field_uri extended_field_uRI def extended_properties!(eprops) - eprops.each {|ep| extended_property!(ep)} + eprops.each { |ep| extended_property!(ep) } end def extended_property!(eprop) nbuild[NS_EWS_TYPES].ExtendedProperty { key = eprop.keys.grep(/extended/i).first - dispatch_field_uri!({key => eprop[key]}, NS_EWS_TYPES) + dispatch_field_uri!({ key => eprop[key] }, NS_EWS_TYPES) if eprop[:values] nbuild.Values { eprop[:values].each do |v| - value! v + value! v end } elsif eprop[:value] @@ -681,11 +680,11 @@ def value!(val) def field_uRI_or_constant(expr) nbuild[NS_EWS_TYPES].FieldURIOrConstant { type = expr.keys.first - self.send(type, expr[type]) + send(type, expr[type]) } end - alias_method :field_uri_or_constant, :field_uRI_or_constant + alias field_uri_or_constant field_uRI_or_constant def constant(expr) nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value]) @@ -694,14 +693,14 @@ def constant(expr) # Build the CalendarView element def calendar_view!(cal_view) attribs = {} - cal_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s} + cal_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end @nbuild[NS_EWS_MESSAGES].CalendarView(attribs) end # Build the ContactsView element def contacts_view!(con_view) attribs = {} - con_view.each_pair {|k,v| attribs[camel_case(k)] = v.to_s} + con_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end @nbuild[NS_EWS_MESSAGES].ContactsView(attribs) end @@ -812,19 +811,17 @@ def saved_item_folder_id!(fid) # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx def item!(item) nbuild.Item { - item.each_pair {|k,v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end def message!(item) nbuild[NS_EWS_TYPES].Message { - if item[:extended_properties] - extended_properties! item.delete(:extended_properties) - end - item.each_pair {|k,v| - self.send("#{k}!", v) + extended_properties! item.delete(:extended_properties) if item[:extended_properties] + item.each_pair { |k, v| + send("#{k}!", v) } } end @@ -835,8 +832,8 @@ def is_read!(read) def calendar_item!(item) nbuild[NS_EWS_TYPES].CalendarItem { - item.each_pair {|k,v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end @@ -848,7 +845,7 @@ def calendar_item_type!(type) def recurrence!(item) nbuild[NS_EWS_TYPES].Recurrence { item.each_pair { |k, v| - self.send("#{k}!", v) + send("#{k}!", v) } } end @@ -856,7 +853,7 @@ def recurrence!(item) def daily_recurrence!(item) nbuild[NS_EWS_TYPES].DailyRecurrence { item.each_pair { |k, v| - self.send("#{k}!", v) + send("#{k}!", v) } } end @@ -864,7 +861,7 @@ def daily_recurrence!(item) def weekly_recurrence!(item) nbuild[NS_EWS_TYPES].WeeklyRecurrence { item.each_pair { |k, v| - self.send("#{k}!", v) + send("#{k}!", v) } } end @@ -876,7 +873,7 @@ def interval!(num) def no_end_recurrence!(item) nbuild[NS_EWS_TYPES].NoEndRecurrence { item.each_pair { |k, v| - self.send("#{k}!", v) + send("#{k}!", v) } } end @@ -884,7 +881,7 @@ def no_end_recurrence!(item) def numbered_recurrence!(item) nbuild[NS_EWS_TYPES].NumberedRecurrence { item.each_pair { |k, v| - self.send("#{k}!", v) + send("#{k}!", v) } } end @@ -893,41 +890,40 @@ def number_of_occurrences!(count) nbuild[NS_EWS_TYPES].NumberOfOccurrences(count) end - def task!(item) nbuild[NS_EWS_TYPES].Task { - item.each_pair {|k, v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end def forward_item!(item) nbuild[NS_EWS_TYPES].ForwardItem { - item.each_pair {|k,v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end def reply_to_item!(item) nbuild[NS_EWS_TYPES].ReplyToItem { - item.each_pair {|k,v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end def reply_all_to_item!(item) nbuild[NS_EWS_TYPES].ReplyAllToItem { - item.each_pair {|k,v| - self.send("#{k}!", v) + item.each_pair { |k, v| + send("#{k}!", v) } } end def reference_item_id!(id) - nbuild[NS_EWS_TYPES].ReferenceItemId {|x| + nbuild[NS_EWS_TYPES].ReferenceItemId { |x| x.parent['Id'] = id[:id] x.parent['ChangeKey'] = id[:change_key] if id[:change_key] } @@ -942,13 +938,13 @@ def importance!(sub) end def body!(b) - nbuild[NS_EWS_TYPES].Body(b[:text]) {|x| + nbuild[NS_EWS_TYPES].Body(b[:text]) { |x| x.parent['BodyType'] = b[:body_type] if b[:body_type] } end def new_body_content!(b) - nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) {|x| + nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) { |x| x.parent['BodyType'] = b[:body_type] if b[:body_type] } end @@ -957,19 +953,19 @@ def new_body_content!(b) # @param [Array] r An array of Mailbox type hashes to send to #mailbox! def to_recipients!(r) nbuild[NS_EWS_TYPES].ToRecipients { - r.each {|mbox| mailbox!(mbox[:mailbox]) } + r.each { |mbox| mailbox!(mbox[:mailbox]) } } end def cc_recipients!(r) nbuild[NS_EWS_TYPES].CcRecipients { - r.each {|mbox| mailbox!(mbox[:mailbox]) } + r.each { |mbox| mailbox!(mbox[:mailbox]) } } end def bcc_recipients!(r) nbuild[NS_EWS_TYPES].BccRecipients { - r.each {|mbox| mailbox!(mbox[:mailbox]) } + r.each { |mbox| mailbox!(mbox[:mailbox]) } } end @@ -981,19 +977,19 @@ def from!(f) def required_attendees!(attendees) nbuild[NS_EWS_TYPES].RequiredAttendees { - attendees.each {|a| attendee!(a[:attendee])} + attendees.each { |a| attendee!(a[:attendee]) } } end def optional_attendees!(attendees) nbuild[NS_EWS_TYPES].OptionalAttendees { - attendees.each {|a| attendee!(a[:attendee])} + attendees.each { |a| attendee!(a[:attendee]) } } end def resources!(attendees) nbuild[NS_EWS_TYPES].Resources { - attendees.each {|a| attendee!(a[:attendee])} + attendees.each { |a| attendee!(a[:attendee]) } } end @@ -1080,8 +1076,9 @@ def updates!(updates) # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx def append_to_item_field!(upd) - uri = upd.select {|k,v| k =~ /_uri/i} - raise EwsBadArgumentError, "Bad argument given for AppendToItemField." if uri.keys.length != 1 + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for AppendToItemField.' if uri.keys.length != 1 + upd.delete(uri.keys.first) @nbuild.AppendToItemField { dispatch_field_uri!(uri) @@ -1091,8 +1088,9 @@ def append_to_item_field!(upd) # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx def set_item_field!(upd) - uri = upd.select {|k,v| k =~ /_uri/i} - raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1 + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 + upd.delete(uri.keys.first) @nbuild[NS_EWS_TYPES].SetItemField { dispatch_field_uri!(uri, NS_EWS_TYPES) @@ -1102,8 +1100,9 @@ def set_item_field!(upd) # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx def delete_item_field!(upd) - uri = upd.select {|k,v| k =~ /_uri/i} - raise EwsBadArgumentError, "Bad argument given for SetItemField." if uri.keys.length != 1 + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 + @nbuild[NS_EWS_TYPES].DeleteItemField { dispatch_field_uri!(uri, NS_EWS_TYPES) } @@ -1153,15 +1152,15 @@ def attachment_ids!(aids) # Build the AttachmentId element # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx def attachment_id!(aid) - attribs = {'Id' => aid} + attribs = { 'Id' => aid } @nbuild[NS_EWS_TYPES].AttachmentId(attribs) end def user_configuration_name!(cfg_name) - attribs = {'Name' => cfg_name.delete(:name)} + attribs = { 'Name' => cfg_name.delete(:name) } @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) { fid = cfg_name.keys.first - self.send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key] + send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key] } end @@ -1175,9 +1174,9 @@ def user_configuration_properties!(cfg_prop) # @param [Hash] fid A folder_id # Ex: {:id => myid, :change_key => ck} def dispatch_folder_id!(fid) - if(fid[:id].is_a?(String)) + if fid[:id].is_a?(String) folder_id!(fid[:id], fid[:change_key]) - elsif(fid[:id].is_a?(Symbol)) + elsif fid[:id].is_a?(Symbol) distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as]) else raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}" @@ -1221,7 +1220,7 @@ def dispatch_update_type!(update) # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI # @todo Implement ExtendedFieldURI - def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES) + def dispatch_field_uri!(uri, ns = NS_EWS_MESSAGES) type = uri.keys.first vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]] case type @@ -1233,14 +1232,17 @@ def dispatch_field_uri!(uri, ns=NS_EWS_MESSAGES) when :indexed_field_uRI, :indexed_field_uri vals.each do |val| nbuild[ns].IndexedFieldURI( - 'FieldURI' => (val[:field_uRI] || val[:field_uri]), + 'FieldURI' => val[:field_uRI] || val[:field_uri], 'FieldIndex' => val[:field_index] ) end when :extended_field_uRI, :extended_field_uri vals.each do |val| nbuild[ns].ExtendedFieldURI { - nbuild.parent['DistinguishedPropertySetId'] = val[:distinguished_property_set_id] if val[:distinguished_property_set_id] + if val[:distinguished_property_set_id] + nbuild.parent['DistinguishedPropertySetId'] = + val[:distinguished_property_set_id] + end nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id] nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag] nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name] @@ -1297,37 +1299,37 @@ def sensitivity!(value) nbuild[NS_EWS_TYPES].Sensitivity(value[:sensitivity]) end -private + private def parent_namespace(node) - node.parent.namespace_definitions.find {|ns| ns.prefix == NS_SOAP} + node.parent.namespace_definitions.find { |ns| ns.prefix == NS_SOAP } end def set_version_header!(version) - if version && !(version == 'none') - nbuild[NS_EWS_TYPES].RequestServerVersion {|x| - x.parent['Version'] = version - } - end + return unless version && !(version == 'none') + + nbuild[NS_EWS_TYPES].RequestServerVersion { |x| + x.parent['Version'] = version + } end def set_impersonation!(type, address) - if type && type != "" - nbuild[NS_EWS_TYPES].ExchangeImpersonation { - nbuild[NS_EWS_TYPES].ConnectingSID { - nbuild[NS_EWS_TYPES].method_missing type, address - } + return unless type && type != '' + + nbuild[NS_EWS_TYPES].ExchangeImpersonation { + nbuild[NS_EWS_TYPES].ConnectingSID { + nbuild[NS_EWS_TYPES].method_missing type, address } - end - end + } + end # Set TimeZoneContext Header # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name} def set_time_zone_context_header!(time_zone_def) - if time_zone_def - nbuild[NS_EWS_TYPES].TimeZoneContext do - time_zone_definition! time_zone_def - end + return unless time_zone_def + + nbuild[NS_EWS_TYPES].TimeZoneContext do + time_zone_definition! time_zone_def end end @@ -1362,6 +1364,5 @@ def format_time(time) raise EwsBadArgumentError, "Invalid Time argument (#{time})" end end - end # EwsBuilder end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_response.rb b/lib/ews/soap/ews_response.rb index b9c3b092..1de29cb6 100644 --- a/lib/ews/soap/ews_response.rb +++ b/lib/ews/soap/ews_response.rb @@ -1,23 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # A Generic Class for SOAP returns. class EwsResponse include Viewpoint::StringUtils @@ -56,10 +53,8 @@ def response_messages @response_messages end - private - def simplify! response_type = response.keys.first response[response_type][:elems][0][:response_messages][:elems].each do |rm| @@ -69,16 +64,10 @@ def simplify! end def class_by_name(cname) - begin - if(cname.instance_of? Symbol) - cname = camel_case(cname) - end - Viewpoint::EWS::SOAP.const_get(cname) - rescue NameError => e - ResponseMessage - end + cname = camel_case(cname) if cname.instance_of? Symbol + Viewpoint::EWS::SOAP.const_get(cname) + rescue NameError + ResponseMessage end - end # EwsSoapResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_soap_availability_response.rb b/lib/ews/soap/ews_soap_availability_response.rb index 0c7527dc..3b9a4c82 100644 --- a/lib/ews/soap/ews_soap_availability_response.rb +++ b/lib/ews/soap/ews_soap_availability_response.rb @@ -1,28 +1,24 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # This is a speciality response class to handle the idiosynracies of # Availability responses. # @attr_reader [String] :message The text from the EWS element class EwsSoapAvailabilityResponse < EwsSoapResponse - def response_messages nil end @@ -39,10 +35,10 @@ def response_message def response_code response_message[:elems][:response_code][:text] end - alias :code :response_code + alias code response_code def response_key - key = body[0].keys.first + body[0].keys.first end private @@ -52,7 +48,5 @@ def simplify! body[0][key] = body[0][key][:elems].inject(:merge) response_message[:elems] = response_message[:elems].inject(:merge) end - end # EwsSoapAvailabilityResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_soap_free_busy_response.rb b/lib/ews/soap/ews_soap_free_busy_response.rb index 5d69909c..7dbeb231 100644 --- a/lib/ews/soap/ews_soap_free_busy_response.rb +++ b/lib/ews/soap/ews_soap_free_busy_response.rb @@ -1,25 +1,21 @@ -=begin - This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Mark McCahill - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Mark McCahill +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - - class EwsSoapFreeBusyResponse < EwsSoapResponse - + class EwsSoapFreeBusyResponse < EwsSoapResponse def initialize(sax_hash) @resp = sax_hash simplify! @@ -61,33 +57,33 @@ def response_message def response_class response_message[:attribs][:response_class] end - alias :status :response_class + alias status response_class def response_code result = find_in_hash_list(response_message[:elems], :response_code) result ? result[:text] : nil end - alias :code :response_code + alias code response_code def response_message_text - guard_hash response_message[:elems], [:message_text, :text] + guard_hash response_message[:elems], %i[message_text text] end - alias :message :response_message_text + alias message response_message_text def response_key response_message[:elems] end def success? - response_class == "Success" + response_class == 'Success' end private def simplify! -# key = response_key -# body[0][key] = body[0][key][:elems].inject(:merge) -# response_message[:elems] = response_message[:elems].inject(:merge) + # key = response_key + # body[0][key] = body[0][key][:elems].inject(:merge) + # response_message[:elems] = response_message[:elems].inject(:merge) end # If the keys don't exist in the Hash return nil @@ -113,7 +109,5 @@ def find_in_hash_list(collection, key) result = collection.find { |hsh| hsh.keys.include?(key) } result ? result[key] : nil end - end # EwsSoapFreeBusyResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_soap_response.rb b/lib/ews/soap/ews_soap_response.rb index 3a8ba4a2..7932e263 100644 --- a/lib/ews/soap/ews_soap_response.rb +++ b/lib/ews/soap/ews_soap_response.rb @@ -1,27 +1,23 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # A Generic Class for SOAP returns. # @attr_reader [String] :message The text from the EWS element class EwsSoapResponse - def initialize(sax_hash) @resp = sax_hash simplify! @@ -45,7 +41,7 @@ def response def response_messages key = response.keys.first - response[key][:elems].find{|e| e.keys.include? :response_messages }[:response_messages][:elems] + response[key][:elems].find { |e| e.keys.include? :response_messages }[:response_messages][:elems] end def response_message @@ -56,26 +52,24 @@ def response_message def response_class response_message[:attribs][:response_class] end - alias :status :response_class + alias status response_class def response_code response_message[:elems][:response_code][:text] end - alias :code :response_code + alias code response_code def response_message_text - guard_hash response_message[:elems], [:message_text, :text] + guard_hash response_message[:elems], %i[message_text text] end - alias :message :response_message_text + alias message response_message_text def success? - response_class == "Success" + response_class == 'Success' end - private - def simplify! response_messages.each do |rm| key = rm.keys.first @@ -97,7 +91,5 @@ def guard_hash(hsh, keys) guard_hash hsh[key], keys end end - end # EwsSoapResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_soap_room_response.rb b/lib/ews/soap/ews_soap_room_response.rb index 6ef56555..cab27265 100644 --- a/lib/ews/soap/ews_soap_room_response.rb +++ b/lib/ews/soap/ews_soap_room_response.rb @@ -1,27 +1,23 @@ -=begin - This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Camille Baldock - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Camille Baldock +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # A class for roomlists SOAP returns. # @attr_reader [String] :message The text from the EWS element class EwsSoapRoomResponse < EwsSoapResponse - def response_messages key = response.keys.first subresponse = response[key][:elems][1] @@ -34,20 +30,18 @@ def roomsArray end def success? - response.first[1][:attribs][:response_class] == "Success" + response.first[1][:attribs][:response_class] == 'Success' end private def simplify! - if response_messages - response_messages.each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) - end + return unless response_messages + + response_messages.each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) end end - end # EwsSoapRoomResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/ews_soap_roomlist_response.rb b/lib/ews/soap/ews_soap_roomlist_response.rb index c96bb20d..e09545fe 100644 --- a/lib/ews/soap/ews_soap_roomlist_response.rb +++ b/lib/ews/soap/ews_soap_roomlist_response.rb @@ -1,27 +1,23 @@ -=begin - This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2013 Camille Baldock - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2013 Camille Baldock +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # A class for roomlists SOAP returns. # @attr_reader [String] :message The text from the EWS element class EwsSoapRoomlistResponse < EwsSoapResponse - def response_messages key = response.keys.first subresponse = response[key][:elems][1] @@ -34,21 +30,18 @@ def roomListsArray end def success? - response.first[1][:attribs][:response_class] == "Success" + response.first[1][:attribs][:response_class] == 'Success' end private - def simplify! - if response_messages - response_messages.each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) - end + return unless response_messages + + response_messages.each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) end end - end # EwsSoapRoomlistResponse - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/exchange_availability.rb b/lib/ews/soap/exchange_availability.rb index 7e81cbda..124a20fc 100644 --- a/lib/ews/soap/exchange_availability.rb +++ b/lib/ews/soap/exchange_availability.rb @@ -1,5 +1,4 @@ module Viewpoint::EWS::SOAP - # Exchange Availability operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx module ExchangeAvailability @@ -18,15 +17,14 @@ def get_user_oof_settings(opts) [:address].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.GetUserOofSettingsRequest {|x| - x.parent.default_namespace = @default_ns - builder.mailbox!(opts) - } + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserOofSettingsRequest { |x| + x.parent.default_namespace = @default_ns + builder.mailbox!(opts) + } end - end + } do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end @@ -41,21 +39,19 @@ def get_user_oof_settings(opts) # @option opts [String,Symbol] :external_audience :none, :known, :all def set_user_oof_settings(opts) opts = opts.clone - [:mailbox, :oof_state].each do |k| + %i[mailbox oof_state].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.SetUserOofSettingsRequest {|x| - x.parent.default_namespace = @default_ns - builder.mailbox! opts.delete(:mailbox) - builder.user_oof_settings!(opts) - } + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.SetUserOofSettingsRequest { |x| + x.parent.default_namespace = @default_ns + builder.mailbox! opts.delete(:mailbox) + builder.user_oof_settings!(opts) + } end - end + } do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - - end #ExchangeAvailability + end # ExchangeAvailability end diff --git a/lib/ews/soap/exchange_data_services.rb b/lib/ews/soap/exchange_data_services.rb index 5ceb3ce3..7cd5ba90 100644 --- a/lib/ews/soap/exchange_data_services.rb +++ b/lib/ews/soap/exchange_data_services.rb @@ -1,5 +1,4 @@ module Viewpoint::EWS::SOAP - # Exchange Data Service operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx module ExchangeDataServices @@ -31,13 +30,12 @@ module ExchangeDataServices # :item_shape => {:base_shape => 'Default'} } def find_item(opts) opts = opts.clone - [:parent_folder_ids, :traversal, :item_shape].each do |k| + %i[parent_folder_ids traversal item_shape].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.FindItem(:Traversal => camel_case(opts[:traversal])) { + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.FindItem(Traversal: camel_case(opts[:traversal])) { builder.nbuild.parent.default_namespace = @default_ns builder.item_shape!(opts[:item_shape]) builder.indexed_page_item_view!(opts[:indexed_page_item_view]) if opts[:indexed_page_item_view] @@ -48,7 +46,7 @@ def find_item(opts) builder.parent_folder_ids!(opts[:parent_folder_ids]) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -71,19 +69,18 @@ def find_item(opts) # ]} def get_item(opts) opts = opts.clone - [:item_shape, :item_ids].each do |k| + %i[item_shape item_ids].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.GetItem { builder.nbuild.parent.default_namespace = @default_ns builder.item_shape!(opts[:item_shape]) builder.item_ids!(opts[:item_ids]) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -127,26 +124,25 @@ def create_item(opts) [:items].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| + req = build_soap! { |type, builder| attribs = {} attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] attribs['SendMeetingInvitations'] = opts[:send_meeting_invitations] if opts[:send_meeting_invitations] - if(type == :header) - else + unless type == :header builder.nbuild.CreateItem(attribs) { builder.nbuild.parent.default_namespace = @default_ns builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] builder.nbuild.Items { - opts[:items].each {|i| + opts[:items].each { |i| # The key can be any number of item types like :message, # :calendar, etc ikey = i.keys.first - builder.send("#{ikey}!",i[ikey]) + builder.send("#{ikey}!", i[ikey]) } } } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -186,20 +182,22 @@ def update_item(opts) [:item_changes].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| + req = build_soap! { |type, builder| attribs = {} attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] attribs['ConflictResolution'] = opts[:conflict_resolution] if opts[:conflict_resolution] - attribs['SendMeetingInvitationsOrCancellations'] = opts[:send_meeting_invitations_or_cancellations] if opts[:send_meeting_invitations_or_cancellations] - if(type == :header) - else + if opts[:send_meeting_invitations_or_cancellations] + attribs['SendMeetingInvitationsOrCancellations'] = + opts[:send_meeting_invitations_or_cancellations] + end + unless type == :header builder.nbuild.UpdateItem(attribs) { builder.nbuild.parent.default_namespace = @default_ns builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] builder.item_changes!(opts[:item_changes]) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -226,21 +224,20 @@ def update_item(opts) # inst.delete_item(opts) def delete_item(opts) opts = opts.clone - [:delete_type, :item_ids].each do |k| + %i[delete_type item_ids].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - attribs = {'DeleteType' => opts[:delete_type]} + req = build_soap! { |type, builder| + attribs = { 'DeleteType' => opts[:delete_type] } attribs['SendMeetingCancellations'] = opts[:send_meeting_cancellations] if opts[:send_meeting_cancellations] attribs['AffectedTaskOccurrences'] = opts[:affected_task_occurrences] if opts[:affected_task_occurrences] - if(type == :header) - else + unless type == :header builder.nbuild.DeleteItem(attribs) { builder.nbuild.parent.default_namespace = @default_ns builder.item_ids!(opts[:item_ids]) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -266,14 +263,13 @@ def delete_item(opts) # obj.move_item(opts) def move_item(opts) opts = opts.clone - [:to_folder_id, :item_ids].each do |k| + %i[to_folder_id item_ids].each do |k| validate_param(opts, k, true) end return_new_ids = validate_param(opts, :return_new_item_ids, false, true) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.MoveItem { builder.nbuild.parent.default_namespace = @default_ns builder.to_folder_id!(opts[:to_folder_id]) @@ -281,7 +277,7 @@ def move_item(opts) builder.return_new_item_ids!(return_new_ids) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -307,14 +303,13 @@ def move_item(opts) # obj.copy_item(opts) def copy_item(opts) opts = opts.clone - [:to_folder_id, :item_ids].each do |k| + %i[to_folder_id item_ids].each do |k| validate_param(opts, k, true) end return_new_ids = validate_param(opts, :return_new_item_ids, false, true) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.CopyItem { builder.nbuild.parent.default_namespace = @default_ns builder.to_folder_id!(opts[:to_folder_id]) @@ -322,7 +317,7 @@ def copy_item(opts) builder.return_new_item_ids!(return_new_ids) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -350,18 +345,17 @@ def send_item(opts) validate_param(opts, k, true) end - req = build_soap! do |type, builder| + req = build_soap! { |type, builder| attribs = {} attribs['SaveItemToFolder'] = validate_param(opts, :save_item_to_folder, false, true) - if(type == :header) - else + unless type == :header builder.nbuild.SendItem(attribs) { builder.nbuild.parent.default_namespace = @default_ns builder.item_ids!(opts[:item_ids]) builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -377,12 +371,9 @@ def export_items(ids) [:item_ids].each do |k| validate_param(ids, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.export_item_ids!(ids[:item_ids]) - end - end + req = build_soap! { |type, builder| + builder.export_item_ids!(ids[:item_ids]) unless type == :header + } do_soap_request(req, response_class: EwsResponse) end @@ -405,16 +396,15 @@ def export_items(ids) # {:folder_id => {:id => 'blah', :change_key => 'blah'}}} def create_folder(opts) opts = opts.clone - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.CreateFolder {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CreateFolder { |x| x.parent.default_namespace = @default_ns builder.parent_folder_id!(opts[:parent_folder_id]) builder.folders!(opts[:folders]) } end - end + } do_soap_request(req) end @@ -426,16 +416,15 @@ def create_folder(opts) # {:id => , :change_key => }, # {:id => , :change_key => } def copy_folder(to_folder_id, *sources) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.CopyFolder { builder.nbuild.parent.default_namespace = @default_ns builder.to_folder_id!(to_folder_id) builder.folder_ids!(sources.flatten) } end - end + } do_soap_request(req) end @@ -452,15 +441,14 @@ def copy_folder(to_folder_id, *sources) # must have been given delegate access to this folder or else this # operation will fail. def delete_folder(opts) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.DeleteFolder('DeleteType' => opts[:delete_type]) { builder.nbuild.parent.default_namespace = @default_ns builder.folder_ids!(opts[:folder_ids], opts[:act_as]) } end - end + } do_soap_request(req) end @@ -485,21 +473,20 @@ def delete_folder(opts) # @todo add FractionalPageFolderView def find_folder(opts) opts = opts.clone - [:parent_folder_ids, :traversal, :folder_shape].each do |k| + %i[parent_folder_ids traversal folder_shape].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.FindFolder(:Traversal => camel_case(opts[:traversal])) { + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.FindFolder(Traversal: camel_case(opts[:traversal])) { builder.nbuild.parent.default_namespace = @default_ns builder.folder_shape!(opts[:folder_shape]) builder.restriction!(opts[:restriction]) if opts[:restriction] builder.parent_folder_ids!(opts[:parent_folder_ids]) } end - end + } do_soap_request(req) end @@ -521,20 +508,19 @@ def find_folder(opts) # :folder_shape => {:base_shape => 'Default'} } def get_folder(opts) opts = opts.clone - [:folder_ids, :folder_shape].each do |k| + %i[folder_ids folder_shape].each do |k| validate_param(opts, k, true) end validate_param(opts[:folder_shape], :base_shape, true) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.GetFolder { builder.nbuild.parent.default_namespace = @default_ns builder.folder_shape!(opts[:folder_shape]) builder.folder_ids!(opts[:folder_ids], opts[:act_as]) } end - end + } do_soap_request(req) end @@ -546,16 +532,15 @@ def get_folder(opts) # {:id => , :change_key => }, # {:id => , :change_key => } def move_folder(to_folder_id, *sources) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.MoveFolder { builder.nbuild.parent.default_namespace = @default_ns builder.to_folder_id!(to_folder_id) builder.folder_ids!(sources.flatten) } end - end + } do_soap_request(req) end @@ -566,9 +551,8 @@ def move_folder(to_folder_id, *sources) # @see http://msdn.microsoft.com/en-us/library/aa580519(v=EXCHG.140).aspx # @param [Array] folder_changes an Array of well formatted Hashes def update_folder(folder_changes) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.UpdateFolder { builder.nbuild.parent.default_namespace = @default_ns builder.nbuild.FolderChanges { @@ -583,7 +567,7 @@ def update_folder(folder_changes) } } end - end + } do_soap_request(req) end @@ -600,20 +584,19 @@ def update_folder(folder_changes) def empty_folder(opts) validate_version(VERSION_2010_SP1) ef_opts = {} - [:delete_type, :delete_sub_folders].each do |k| + %i[delete_type delete_sub_folders].each do |k| ef_opts[camel_case(k)] = validate_param(opts, k, true) end fids = validate_param opts, :folder_ids, true - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.EmptyFolder(ef_opts) {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.EmptyFolder(ef_opts) { |_x| builder.nbuild.parent.default_namespace = @default_ns builder.folder_ids!(fids) } end - end + } do_soap_request(req) end @@ -633,15 +616,14 @@ def get_attachment(opts) [:attachment_ids].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.GetAttachment {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetAttachment { |_x| builder.nbuild.parent.default_namespace = @default_ns builder.attachment_ids!(opts[:attachment_ids]) } end - end + } do_soap_request(req) end @@ -662,10 +644,9 @@ def create_attachment(opts) validate_param(opts, :files, false, []) validate_param(opts, :items, false, []) - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.CreateAttachment {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CreateAttachment { |x| builder.nbuild.parent.default_namespace = @default_ns builder.parent_item_id!(opts[:parent_id]) x.Attachments { @@ -681,11 +662,10 @@ def create_attachment(opts) } } end - end + } do_soap_request(req, response_class: EwsResponse) end - # ------------ Utility Operations ------------ # Exposes the full membership of distribution lists. @@ -700,19 +680,18 @@ def create_attachment(opts) # {:id => 'my id'} def expand_dl(opts) opts = opts.clone - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.ExpandDL {|x| - x.parent.default_namespace = @default_ns - x.Mailbox {|mb| - key = :email_address - mb[NS_EWS_TYPES].EmailAddress(opts[key]) if opts[key] - builder.item_id! if opts[:item_id] + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ExpandDL { |x| + x.parent.default_namespace = @default_ns + x.Mailbox { |mb| + key = :email_address + mb[NS_EWS_TYPES].EmailAddress(opts[key]) if opts[key] + builder.item_id! if opts[:item_id] + } } - } end - end + } do_soap_request(req) end @@ -732,18 +711,17 @@ def expand_dl(opts) def resolve_names(opts) opts = opts.clone fcd = opts.has_key?(:full_contact_data) ? opts[:full_contact_data] : true - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.ResolveNames {|x| - x.parent['ReturnFullContactData'] = fcd.to_s - x.parent['SearchScope'] = opts[:search_scope] if opts[:search_scope] - x.parent.default_namespace = @default_ns - # @todo builder.nbuild.ParentFolderIds - x.UnresolvedEntry(opts[:name]) - } + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ResolveNames { |x| + x.parent['ReturnFullContactData'] = fcd.to_s + x.parent['SearchScope'] = opts[:search_scope] if opts[:search_scope] + x.parent.default_namespace = @default_ns + # @todo builder.nbuild.ParentFolderIds + x.UnresolvedEntry(opts[:name]) + } end - end + } do_soap_request(req) end @@ -753,14 +731,13 @@ def resolve_names(opts) def convert_id(opts) opts = opts.clone - [:id, :format, :destination_format, :mailbox ].each do |k| + %i[id format destination_format mailbox].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.ConvertId {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ConvertId { |x| builder.nbuild.parent.default_namespace = @default_ns x.parent['DestinationFormat'] = opts[:destination_format].to_s.camel_case x.SourceIds { |x| @@ -772,9 +749,8 @@ def convert_id(opts) } } end - end + } do_soap_request(req, response_class: EwsResponse) end - - end #ExchangeDataServices + end # ExchangeDataServices end diff --git a/lib/ews/soap/exchange_notification.rb b/lib/ews/soap/exchange_notification.rb index 626a6159..717dfd27 100644 --- a/lib/ews/soap/exchange_notification.rb +++ b/lib/ews/soap/exchange_notification.rb @@ -1,23 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # Exchange Notification operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx module ExchangeNotification @@ -47,22 +44,19 @@ module ExchangeNotification # }}, # ] def subscribe(subscriptions) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.Subscribe { builder.nbuild.parent.default_namespace = @default_ns subscriptions.each do |sub| subtype = sub.keys.first - if(builder.respond_to?(subtype)) - builder.send subtype, sub[subtype] - else - raise EwsBadArgumentError, "Bad subscription type. #{subtype}" - end + raise EwsBadArgumentError, "Bad subscription type. #{subtype}" unless builder.respond_to?(subtype) + + builder.send subtype, sub[subtype] end } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -71,15 +65,14 @@ def subscribe(subscriptions) # # @param [String] subscription_id The Id of the subscription def unsubscribe(subscription_id) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.Unsubscribe { builder.nbuild.parent.default_namespace = @default_ns builder.subscription_id!(subscription_id) } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -89,20 +82,18 @@ def unsubscribe(subscription_id) # @param [String] subscription_id Subscription identifier # @param [String] watermark Event bookmark in the events queue def get_events(subscription_id, watermark) - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.GetEvents { builder.nbuild.parent.default_namespace = @default_ns builder.subscription_id!(subscription_id) builder.watermark!(watermark, NS_EWS_MESSAGES) } end - end + } do_soap_request(req, response_class: EwsResponse) end - # ------- convenience methods ------- # # Create a pull subscription to a single folder @@ -113,13 +104,13 @@ def get_events(subscription_id, watermark) def pull_subscribe_folder(folder, evtypes, timeout = nil, watermark = nil) timeout ||= 240 # 4 hour default timeout psr = { - :subscribe_to_all_folders => false, - :folder_ids => [ {:id => folder[:id], :change_key => folder[:change_key]} ], - :event_types=> evtypes, - :timeout => timeout + subscribe_to_all_folders: false, + folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], + event_types: evtypes, + timeout: timeout } psr[:watermark] = watermark if watermark - subscribe([{pull_subscription_request: psr}]) + subscribe([{ pull_subscription_request: psr }]) end # Create a push subscription to a single folder @@ -131,16 +122,14 @@ def pull_subscribe_folder(folder, evtypes, timeout = nil, watermark = nil) def push_subscribe_folder(folder, evtypes, url, status_frequency = nil, watermark = nil) status_frequency ||= 30 psr = { - :subscribe_to_all_folders => false, - :folder_ids => [ {:id => folder[:id], :change_key => folder[:change_key]} ], - :event_types=> evtypes, - :status_frequency => status_frequency, - :uRL => url.to_s + subscribe_to_all_folders: false, + folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], + event_types: evtypes, + status_frequency: status_frequency, + uRL: url.to_s } psr[:watermark] = watermark if watermark - subscribe([{push_subscription_request: psr}]) + subscribe([{ push_subscription_request: psr }]) end - - - end #ExchangeNotification + end # ExchangeNotification end diff --git a/lib/ews/soap/exchange_synchronization.rb b/lib/ews/soap/exchange_synchronization.rb index 380a488c..1ad63544 100644 --- a/lib/ews/soap/exchange_synchronization.rb +++ b/lib/ews/soap/exchange_synchronization.rb @@ -1,23 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - # Exchange Synchronization operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx module ExchangeSynchronization @@ -35,9 +32,8 @@ module ExchangeSynchronization # first time syncing this does not need to be passed. def sync_folder_hierarchy(opts) opts = opts.clone - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.SyncFolderHierarchy { builder.nbuild.parent.default_namespace = @default_ns builder.folder_shape!(opts[:folder_shape]) @@ -45,7 +41,7 @@ def sync_folder_hierarchy(opts) builder.sync_state!(opts[:sync_state]) if opts[:sync_state] } end - end + } do_soap_request(req, response_class: EwsResponse) end @@ -72,9 +68,8 @@ def sync_folder_hierarchy(opts) # :max_changes_returned => 256 } def sync_folder_items(opts) opts = opts.clone - req = build_soap! do |type, builder| - if(type == :header) - else + req = build_soap! { |type, builder| + unless type == :header builder.nbuild.SyncFolderItems { builder.nbuild.parent.default_namespace = @default_ns builder.item_shape!(opts[:item_shape]) @@ -85,9 +80,8 @@ def sync_folder_items(opts) builder.sync_scope!(opts[:sync_scope]) if opts[:sync_scope] } end - end + } do_soap_request(req, response_class: EwsResponse) end - - end #ExchangeSynchronization + end # ExchangeSynchronization end diff --git a/lib/ews/soap/exchange_time_zones.rb b/lib/ews/soap/exchange_time_zones.rb index 31876e5e..15f52414 100644 --- a/lib/ews/soap/exchange_time_zones.rb +++ b/lib/ews/soap/exchange_time_zones.rb @@ -1,5 +1,4 @@ module Viewpoint::EWS::SOAP - module ExchangeTimeZones include Viewpoint::EWS::SOAP @@ -12,29 +11,25 @@ module ExchangeTimeZones # zones = ews_client.ews.get_time_zones # @todo Implement TimeZoneDefinition with sub elements Periods, TransitionsGroups and Transitions def get_time_zones(full = false, ids = nil) - req = build_soap! do |type, builder| - unless type == :header - builder.get_server_time_zones!(full: full, ids: ids) - end - end + req = build_soap! { |type, builder| + builder.get_server_time_zones!(full: full, ids: ids) unless type == :header + } result = do_soap_request req, response_class: EwsSoapResponse - if result.success? - zones = [] - result.response_messages.each do |message| - elements = message[:get_server_time_zones_response_message][:elems][:time_zone_definitions][:elems] - elements.each do |definition| - data = { - id: definition[:time_zone_definition][:attribs][:id], - name: definition[:time_zone_definition][:attribs][:name] - } - zones << OpenStruct.new(data) - end + raise EwsError, 'Could not get time zones' unless result.success? + + zones = [] + result.response_messages.each do |message| + elements = message[:get_server_time_zones_response_message][:elems][:time_zone_definitions][:elems] + elements.each do |definition| + data = { + id: definition[:time_zone_definition][:attribs][:id], + name: definition[:time_zone_definition][:attribs][:name] + } + zones << OpenStruct.new(data) end - zones - else - raise EwsError, "Could not get time zones" end + zones end # Sets the time zone context header @@ -45,12 +40,7 @@ def get_time_zones(full = false, ids = nil) # # subsequent request will send the TimeZoneContext header # @see EWSClient#set_time_zone def set_time_zone_context(id) - if id - @time_zone_context = {id: id} - else - @time_zone_context = nil - end + @time_zone_context = ({ id: id } if id) end - end end diff --git a/lib/ews/soap/exchange_user_configuration.rb b/lib/ews/soap/exchange_user_configuration.rb index 4e98e711..4551005c 100644 --- a/lib/ews/soap/exchange_user_configuration.rb +++ b/lib/ews/soap/exchange_user_configuration.rb @@ -1,5 +1,4 @@ module Viewpoint::EWS::SOAP - # Exchange User Configuration operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx module ExchangeUserConfiguration @@ -9,25 +8,23 @@ module ExchangeUserConfiguration # a folder. # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx # @param [Hash] opts - # @option opts [Hash] :user_config_name + # @option opts [Hash] :user_config_name # @option opts [String] :user_config_props def get_user_configuration(opts) opts = opts.clone - [:user_config_name, :user_config_props].each do |k| + %i[user_config_name user_config_props].each do |k| validate_param(opts, k, true) end - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.GetUserConfiguration {|x| - x.parent.default_namespace = @default_ns - builder.user_configuration_name!(opts[:user_config_name]) - builder.user_configuration_properties!(opts[:user_config_props]) - } + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserConfiguration { |x| + x.parent.default_namespace = @default_ns + builder.user_configuration_name!(opts[:user_config_name]) + builder.user_configuration_properties!(opts[:user_config_props]) + } end - end + } do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - - end #ExchangeUserConfiguration + end # ExchangeUserConfiguration end diff --git a/lib/ews/soap/exchange_web_service.rb b/lib/ews/soap/exchange_web_service.rb index 02b6be75..579909f4 100644 --- a/lib/ews/soap/exchange_web_service.rb +++ b/lib/ews/soap/exchange_web_service.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class ExchangeWebService @@ -28,7 +26,8 @@ class ExchangeWebService include ExchangeSynchronization include ExchangeTimeZones - attr_accessor :server_version, :auto_deepen, :no_auto_deepen_behavior, :connection, :impersonation_type, :impersonation_address + attr_accessor :server_version, :auto_deepen, :no_auto_deepen_behavior, :connection, :impersonation_type, + :impersonation_address # @param [Viewpoint::EWS::Connection] connection the connection object # @param [Hash] opts additional options to the web service @@ -39,26 +38,26 @@ class ExchangeWebService def initialize(connection, opts = {}) super() @connection = connection - @server_version = opts[:server_version] ? opts[:server_version] : VERSION_2010 + @server_version = opts[:server_version] || VERSION_2010 @auto_deepen = true @no_auto_deepen_behavior = :raise - @impersonation_type = "" - @impersonation_address = "" + @impersonation_type = '' + @impersonation_address = '' end def delete_attachment action = "#{SOAP_ACTION_PREFIX}/DeleteAttachment" - resp = invoke("#{NS_EWS_MESSAGES}:DeleteAttachment", action) do |delete_attachment| + resp = invoke("#{NS_EWS_MESSAGES}:DeleteAttachment", action) { |delete_attachment| build_delete_attachment!(delete_attachment) - end + } parse_delete_attachment(resp) end def create_managed_folder action = "#{SOAP_ACTION_PREFIX}/CreateManagedFolder" - resp = invoke("#{NS_EWS_MESSAGES}:CreateManagedFolder", action) do |create_managed_folder| + resp = invoke("#{NS_EWS_MESSAGES}:CreateManagedFolder", action) { |create_managed_folder| build_create_managed_folder!(create_managed_folder) - end + } parse_create_managed_folder(resp) end @@ -68,12 +67,12 @@ def create_managed_folder # @param [String] owner The user that is delegating permissions def get_delegate(owner) action = "#{SOAP_ACTION_PREFIX}/GetDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:GetDelegate", action) do |root| + resp = invoke("#{NS_EWS_MESSAGES}:GetDelegate", action) { |root| root.set_attr('IncludePermissions', 'true') build!(root) do - mailbox!(root, {:email_address => {:text => owner}}) + mailbox!(root, { email_address: { text: owner } }) end - end + } parse_soap_response(resp) end @@ -86,11 +85,11 @@ def get_delegate(owner) # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. def add_delegate(owner, delegate, permissions) action = "#{SOAP_ACTION_PREFIX}/AddDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:AddDelegate", action) do |root| + resp = invoke("#{NS_EWS_MESSAGES}:AddDelegate", action) { |root| build!(root) do add_delegate!(owner, delegate, permissions) end - end + } parse_soap_response(resp) end @@ -101,11 +100,11 @@ def add_delegate(owner, delegate, permissions) # @param [String] delegate The user that is being given delegate permission def remove_delegate(owner, delegate) action = "#{SOAP_ACTION_PREFIX}/RemoveDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:RemoveDelegate", action) do |root| + resp = invoke("#{NS_EWS_MESSAGES}:RemoveDelegate", action) { |root| build!(root) do remove_delegate!(owner, delegate) end - end + } parse_soap_response(resp) end @@ -118,11 +117,11 @@ def remove_delegate(owner, delegate) # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. def update_delegate(owner, delegate, permissions) action = "#{SOAP_ACTION_PREFIX}/UpdateDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:UpdateDelegate", action) do |root| + resp = invoke("#{NS_EWS_MESSAGES}:UpdateDelegate", action) { |root| build!(root) do add_delegate!(owner, delegate, permissions) end - end + } parse_soap_response(resp) end @@ -148,22 +147,21 @@ def update_delegate(owner, delegate, permissions) # @todo Finish out :suggestions_view_options def get_user_availability(opts) opts = opts.clone - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.GetUserAvailabilityRequest {|x| - x.parent.default_namespace = @default_ns - builder.time_zone!(opts[:time_zone]) - builder.nbuild.MailboxDataArray { - opts[:mailbox_data].each do |mbd| - builder.mailbox_data!(mbd) - end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserAvailabilityRequest { |x| + x.parent.default_namespace = @default_ns + builder.time_zone!(opts[:time_zone]) + builder.nbuild.MailboxDataArray do + opts[:mailbox_data].each do |mbd| + builder.mailbox_data!(mbd) + end + end + builder.free_busy_view_options!(opts[:free_busy_view_options]) + builder.suggestions_view_options!(opts[:suggestions_view_options]) } - builder.free_busy_view_options!(opts[:free_busy_view_options]) - builder.suggestions_view_options!(opts[:suggestions_view_options]) - } end - end + } do_soap_request(req, response_class: EwsSoapFreeBusyResponse) end @@ -172,27 +170,23 @@ def get_user_availability(opts) # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx # @param [string] roomDistributionList def get_rooms(roomDistributionList) - req = build_soap! do |type, builder| - if(type == :header) - else - builder.nbuild.GetRooms {|x| + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetRooms { |x| x.parent.default_namespace = @default_ns builder.room_list!(roomDistributionList) } end - end + } do_soap_request(req, response_class: EwsSoapRoomResponse) end # Gets the room lists that are available within the Exchange organization. # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx def get_room_lists - req = build_soap! do |type, builder| - if(type == :header) - else - builder.room_lists! - end - end + req = build_soap! { |type, builder| + builder.room_lists! unless type == :header + } do_soap_request(req, response_class: EwsSoapRoomlistResponse) end @@ -216,13 +210,14 @@ def do_soap_request(soapmsg, opts = {}) # @param [Hash] opts misc options to send to the parser # @option opts [Class] :response_class the response class def parse_soap_response(soapmsg, opts = {}) - raise EwsError, "Can't parse an empty response. Please check your endpoint." if(soapmsg.nil?) + raise EwsError, "Can't parse an empty response. Please check your endpoint." if soapmsg.nil? + opts[:response_class] ||= EwsSoapResponse EwsParser.new(soapmsg).parse(opts) end - private + # Private Methods (Builders and Parsers) # Validate or set default values for options parameters. @@ -234,9 +229,11 @@ def parse_soap_response(soapmsg, opts = {}) def validate_param(opts, key, required, default_val = nil) if required raise EwsBadArgumentError, "Required parameter(#{key}) not passed." unless opts.has_key?(key) + opts[key] else - raise EwsBadArgumentError, "Default value not supplied." unless default_val + raise EwsBadArgumentError, 'Default value not supplied.' unless default_val + opts.has_key?(key) ? opts[key] : default_val end end @@ -245,20 +242,20 @@ def validate_param(opts, key, required, default_val = nil) # This method should be called with the required version and we'll throw # an exception of the currently set @server_version does not comply. def validate_version(exchange_version) - if server_version < exchange_version - msg = 'The operation you are attempting to use is not compatible with' - msg << " your configured Exchange Server version(#{server_version})." - msg << " You must be running at least version (#{exchange_version})." - raise EwsServerVersionError, msg - end + return unless server_version < exchange_version + + msg = 'The operation you are attempting to use is not compatible with' + msg << " your configured Exchange Server version(#{server_version})." + msg << " You must be running at least version (#{exchange_version})." + raise EwsServerVersionError, msg end # Build the common elements in the SOAP message and yield to any custom elements. def build_soap!(&block) - opts = { :server_version => server_version, :impersonation_type => impersonation_type, :impersonation_mail => impersonation_address } + opts = { server_version: server_version, impersonation_type: impersonation_type, +impersonation_mail: impersonation_address } opts[:time_zone_context] = @time_zone_context if @time_zone_context EwsBuilder.new.build!(opts, &block) end - end # class ExchangeWebService end # Viewpoint diff --git a/lib/ews/soap/parsers/ews_parser.rb b/lib/ews/soap/parsers/ews_parser.rb index 4eb2246e..72afde56 100644 --- a/lib/ews/soap/parsers/ews_parser.rb +++ b/lib/ews/soap/parsers/ews_parser.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class EwsParser @@ -38,6 +36,5 @@ def parse(opts = {}) def sax_parser @parser ||= Nokogiri::XML::SAX::Parser.new(@sax_doc) end - end # EwsParser end # Viewpoint diff --git a/lib/ews/soap/parsers/ews_sax_document.rb b/lib/ews/soap/parsers/ews_sax_document.rb index e2a3a427..03d5333b 100644 --- a/lib/ews/soap/parsers/ews_sax_document.rb +++ b/lib/ews/soap/parsers/ews_sax_document.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP # Parse the incoming response document via a SAX parser instead of the @@ -35,8 +33,9 @@ def characters(string) # FIXME: Move white space removal to somewhere else. # This function can be called multiple times. In this case newlines in Text Bodies get stripped. # See: https://github.com/zenchild/Viewpoint/issues/90 - #string.strip! + # string.strip! return if string.empty? + if @elems.last[:text] @elems.last[:text] += string else @@ -44,27 +43,26 @@ def characters(string) end end - def start_element_namespace(name, attributes = [], prefix = nil, uri = nil, ns = []) - name = ruby_case(name).to_sym + def start_element_namespace(name, attributes = [], _prefix = nil, _uri = nil, _ns = []) + ruby_case(name).to_sym elem = {} unless attributes.empty? - elem[:attribs] = attributes.collect{|a| - { ruby_case(a.localname).to_sym => a.value} + elem[:attribs] = attributes.collect { |a| + { ruby_case(a.localname).to_sym => a.value } }.inject(&:merge) end @elems << elem end - def end_element_namespace name, prefix=nil, uri=nil + def end_element_namespace(name, _prefix = nil, _uri = nil) name = ruby_case(name).to_sym elem = @elems.pop if @elems.empty? @struct[name] = elem else @elems.last[:elems] = [] unless @elems.last[:elems].is_a?(Array) - @elems.last[:elems] << {name => elem} + @elems.last[:elems] << { name => elem } end end - end end diff --git a/lib/ews/soap/response_message.rb b/lib/ews/soap/response_message.rb index 8814abe9..39346e78 100644 --- a/lib/ews/soap/response_message.rb +++ b/lib/ews/soap/response_message.rb @@ -1,24 +1,21 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class ResponseMessage - attr_reader :message, :type def initialize(message) @@ -29,33 +26,31 @@ def initialize(message) def response_class message[:attribs][:response_class] end - alias :status :response_class + alias status response_class def success? response_class == 'Success' end def message_text - safe_hash_access message, [:elems, :message_text, :text] + safe_hash_access message, %i[elems message_text text] end def response_code - safe_hash_access message, [:elems, :response_code, :text] + safe_hash_access message, %i[elems response_code text] end - alias :code :response_code + alias code response_code def message_xml - safe_hash_access message, [:elems, :message_xml, :text] + safe_hash_access message, %i[elems message_xml text] end def items - safe_hash_access(message, [:elems, :items, :elems]) || [] + safe_hash_access(message, %i[elems items elems]) || [] end - private - def safe_hash_access(hsh, keys) key = keys.shift return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) @@ -66,7 +61,6 @@ def safe_hash_access(hsh, keys) safe_hash_access hsh[key], keys end end - end end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/create_attachment_response_message.rb b/lib/ews/soap/responses/create_attachment_response_message.rb index 80bdde1b..0b38b558 100644 --- a/lib/ews/soap/responses/create_attachment_response_message.rb +++ b/lib/ews/soap/responses/create_attachment_response_message.rb @@ -1,37 +1,32 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - class CreateAttachmentResponseMessage < ResponseMessage include Viewpoint::StringUtils def attachments return @attachments if @attachments - a = safe_hash_access message, [:elems, :attachments, :elems] + a = safe_hash_access message, %i[elems attachments elems] @attachments = a.nil? ? nil : parse_attachments(a) end - private - def parse_attachments(att) att.collect do |a| type = a.keys.first @@ -41,7 +36,5 @@ def parse_attachments(att) klass.new(item, a[type]) end end - end # CreateAttachmentResponseMessage - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/create_item_response_message.rb b/lib/ews/soap/responses/create_item_response_message.rb index 946fb242..a7ba9b56 100644 --- a/lib/ews/soap/responses/create_item_response_message.rb +++ b/lib/ews/soap/responses/create_item_response_message.rb @@ -1,25 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - class CreateItemResponseMessage < ResponseMessage - end # CreateItemResponseMessage - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/find_item_response_message.rb b/lib/ews/soap/responses/find_item_response_message.rb index da717cd9..2d581089 100644 --- a/lib/ews/soap/responses/find_item_response_message.rb +++ b/lib/ews/soap/responses/find_item_response_message.rb @@ -1,25 +1,21 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP - class RootFolder - attr_reader :root def initialize(root) @@ -54,27 +50,21 @@ def groups root[:elems][0][:groups][:elems] end - private - def attrib(key) return nil unless root.has_key?(:attribs) + root[:attribs][key] end - end - class FindItemResponseMessage < ResponseMessage - def root_folder return @root_folder if @root_folder - rf = safe_hash_access message, [:elems, :root_folder] + rf = safe_hash_access message, %i[elems root_folder] @root_folder = rf.nil? ? nil : RootFolder.new(rf) end - end # FindItemResponseMessage - end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/get_events_response_message.rb b/lib/ews/soap/responses/get_events_response_message.rb index 4f75fbdd..c7cfbd62 100644 --- a/lib/ews/soap/responses/get_events_response_message.rb +++ b/lib/ews/soap/responses/get_events_response_message.rb @@ -1,53 +1,47 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class GetEventsResponseMessage < ResponseMessage - def notification - safe_hash_access message, [:elems, :notification, :elems] + safe_hash_access message, %i[elems notification elems] end def subscription_id - safe_hash_access notification[0], [:subscription_id, :text] + safe_hash_access notification[0], %i[subscription_id text] end def previous_watermark - safe_hash_access notification[1], [:previous_watermark, :text] + safe_hash_access notification[1], %i[previous_watermark text] end def new_watermark ev = notification.last - if ev - type = ev.keys.first - ev[type][:elems][0][:watermark][:text] - else - nil - end + return unless ev + + type = ev.keys.first + ev[type][:elems][0][:watermark][:text] end def more_events? - safe_hash_access(notification[2], [:more_events, :text]) == 'true' + safe_hash_access(notification[2], %i[more_events text]) == 'true' end def events notification[3..-1] end - end # GetEventsResponseMessage end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/send_notification_response_message.rb b/lib/ews/soap/responses/send_notification_response_message.rb index 0071d5d5..4a471565 100644 --- a/lib/ews/soap/responses/send_notification_response_message.rb +++ b/lib/ews/soap/responses/send_notification_response_message.rb @@ -1,59 +1,54 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class SendNotificationResponseMessage < ResponseMessage include Viewpoint::StringUtils def notification - safe_hash_access message, [:elems, :notification, :elems] + safe_hash_access message, %i[elems notification elems] end def subscription_id - safe_hash_access notification[0], [:subscription_id, :text] + safe_hash_access notification[0], %i[subscription_id text] end def previous_watermark - safe_hash_access notification[1], [:previous_watermark, :text] + safe_hash_access notification[1], %i[previous_watermark text] end def new_watermark ev = notification.last - if ev - type = ev.keys.first - ev[type][:elems][0][:watermark][:text] - else - nil - end + return unless ev + + type = ev.keys.first + ev[type][:elems][0][:watermark][:text] end def more_events? - safe_hash_access(notification[2], [:more_events, :text]) == 'true' + safe_hash_access(notification[2], %i[more_events text]) == 'true' end def events @events ||= - notification[3..-1].collect do |ev| + notification[3..-1].collect { |ev| type = ev.keys.first klass = Viewpoint::EWS::Types.const_get(camel_case(type)) klass.new(nil, ev[type]) - end + } end - end # SendNotificationResponseMessage end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/subscribe_response_message.rb b/lib/ews/soap/responses/subscribe_response_message.rb index 3987fda6..f8c181f8 100644 --- a/lib/ews/soap/responses/subscribe_response_message.rb +++ b/lib/ews/soap/responses/subscribe_response_message.rb @@ -1,35 +1,31 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class SubscribeResponseMessage < ResponseMessage - def subscription safe_hash_access message, [:elems] end def subscription_id - safe_hash_access subscription, [:subscription_id, :text] + safe_hash_access subscription, %i[subscription_id text] end def watermark - safe_hash_access subscription, [:watermark, :text] + safe_hash_access subscription, %i[watermark text] end - end # SubscribeResponseMessage end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb index 753d99fc..7c298bff 100644 --- a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb @@ -1,36 +1,32 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class SyncFolderHierarchyResponseMessage < ResponseMessage - def sync_state - safe_hash_access message, [:elems, :sync_state, :text] + safe_hash_access message, %i[elems sync_state text] end def includes_last_folder_in_range? - ans = safe_hash_access message, [:elems, :includes_last_folder_in_range, :text] + ans = safe_hash_access message, %i[elems includes_last_folder_in_range text] ans.downcase == 'true' end def changes - safe_hash_access(message, [:elems, :changes, :elems]) || [] + safe_hash_access(message, %i[elems changes elems]) || [] end - end # SyncFolderHierarchyResponseMessage end # Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/responses/sync_folder_items_response_message.rb b/lib/ews/soap/responses/sync_folder_items_response_message.rb index d4d8194b..550ed2eb 100644 --- a/lib/ews/soap/responses/sync_folder_items_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_items_response_message.rb @@ -1,36 +1,32 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::SOAP class SyncFolderItemsResponseMessage < ResponseMessage - def sync_state - safe_hash_access message, [:elems, :sync_state, :text] + safe_hash_access message, %i[elems sync_state text] end def includes_last_item_in_range? - ans = safe_hash_access message, [:elems, :includes_last_item_in_range, :text] + ans = safe_hash_access message, %i[elems includes_last_item_in_range text] ans.downcase == 'true' end def changes - safe_hash_access(message, [:elems, :changes, :elems]) || [] + safe_hash_access(message, %i[elems changes elems]) || [] end - end # SyncFolderItemsResponseMessage end # Viewpoint::EWS::SOAP diff --git a/lib/ews/templates/calendar_item.rb b/lib/ews/templates/calendar_item.rb index 0c582148..221c75fe 100644 --- a/lib/ews/templates/calendar_item.rb +++ b/lib/ews/templates/calendar_item.rb @@ -1,23 +1,21 @@ module Viewpoint::EWS module Template - # Template for creating CalendarItems - # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx - class CalendarItem < OpenStruct - + # Template for creating CalendarItems + # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx + class CalendarItem < OpenStruct # Available parameters with the required ordering - PARAMETERS = %w{mime_content item_id parent_folder_id item_class subject sensitivity body attachments - date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend is_unmodified - internet_message_headers date_time_sent date_time_created response_objects reminder_due_by reminder_is_set - reminder_minutes_before_start display_cc display_to has_attachments extended_property culture start end - original_start is_all_day_event legacy_free_busy_status location when is_meeting is_cancelled is_recurring - meeting_request_was_sent is_response_requested calendar_item_type my_response_type organizer - required_attendees optional_attendees resources conflicting_meeting_count adjacent_meeting_count - conflicting_meetings adjacent_meetings duration time_zone appointment_reply_time appointment_sequence_number - appointment_state recurrence first_occurrence last_occurrence modified_occurrences deleted_occurrences - meeting_time_zone start_time_zone end_time_zone conference_type allow_new_time_proposal is_online_meeting - meeting_workspace_url net_show_url effective_rights last_modified_name last_modified_time is_associated - web_client_read_form_query_string web_client_edit_form_query_string conversation_id unique_body - }.map(&:to_sym).freeze + PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments + date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend is_unmodified + internet_message_headers date_time_sent date_time_created response_objects reminder_due_by reminder_is_set + reminder_minutes_before_start display_cc display_to has_attachments extended_property culture start end + original_start is_all_day_event legacy_free_busy_status location when is_meeting is_cancelled is_recurring + meeting_request_was_sent is_response_requested calendar_item_type my_response_type organizer + required_attendees optional_attendees resources conflicting_meeting_count adjacent_meeting_count + conflicting_meetings adjacent_meetings duration time_zone appointment_reply_time appointment_sequence_number + appointment_state recurrence first_occurrence last_occurrence modified_occurrences deleted_occurrences + meeting_time_zone start_time_zone end_time_zone conference_type allow_new_time_proposal is_online_meeting + meeting_workspace_url net_show_url effective_rights last_modified_name last_modified_time is_associated + web_client_read_form_query_string web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze # Returns a new CalendarItem template def initialize(opts = {}) @@ -30,17 +28,18 @@ def to_ews_create(opts = {}) structure = {} structure[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') # options - structure[:send_meeting_invitations] = (opts.has_key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') + structure[:send_meeting_invitations] = + (opts.has_key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') - if self.saved_item_folder_id - if self.saved_item_folder_id.kind_of?(Hash) - structure[:saved_item_folder_id] = saved_item_folder_id - else - structure[:saved_item_folder_id] = {id: saved_item_folder_id} - end + if saved_item_folder_id + structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end end - structure[:items] = [{calendar_item: to_ews_item}] + structure[:items] = [{ calendar_item: to_ews_item }] structure end @@ -51,29 +50,27 @@ def to_ews_create(opts = {}) def to_ews_item item_parameters = {} PARAMETERS.each do |key| - if !(value = self.send(key)).nil? - - # Convert non duplicable values to String - case value - when NilClass, FalseClass, TrueClass, Symbol, Numeric - value = value.to_s - end + next if (value = send(key)).nil? - # Convert attributes - case key - when :start, :end - item_parameters[key] = {text: value.respond_to?(:iso8601) ? value.iso8601 : value} - when :body - item_parameters[key] = {body_type: self.body_type || 'Text', text: value.to_s} - else - item_parameters[key] = value - end + # Convert non duplicable values to String + case value + when NilClass, FalseClass, TrueClass, Symbol, Numeric + value = value.to_s end + + # Convert attributes + item_parameters[key] = case key + when :start, :end + { text: value.respond_to?(:iso8601) ? value.iso8601 : value } + when :body + { body_type: body_type || 'Text', text: value.to_s } + else + value + end end item_parameters end - end end end diff --git a/lib/ews/templates/forward_item.rb b/lib/ews/templates/forward_item.rb index 75985502..b473920f 100644 --- a/lib/ews/templates/forward_item.rb +++ b/lib/ews/templates/forward_item.rb @@ -1,24 +1,21 @@ module Viewpoint::EWS module Template class ForwardItem < Message - # Format this object for EWS backend consumption. def to_ews ews_opts, msg = to_ews_basic msg[:reference_item_id] = reference_item_id - msg[:new_body_content] = {text: new_body_content, body_type: new_body_type} - ews_opts.merge({items: [{forward_item: msg}]}) + msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } + ews_opts.merge({ items: [{ forward_item: msg }] }) end private - def init_defaults! super self.new_body_content ||= '' self.new_body_type ||= 'Text' end - end end end diff --git a/lib/ews/templates/message.rb b/lib/ews/templates/message.rb index 2297c8ae..add1be6a 100644 --- a/lib/ews/templates/message.rb +++ b/lib/ews/templates/message.rb @@ -1,7 +1,6 @@ module Viewpoint::EWS module Template class Message < OpenStruct - def initialize(opts = {}) super opts.clone init_defaults! @@ -10,17 +9,15 @@ def initialize(opts = {}) # Format this object for EWS backend consumption. def to_ews ews_opts, msg = to_ews_basic - ews_opts.merge({items: [{message: msg}]}) + ews_opts.merge({ items: [{ message: msg }] }) end def has_attachments? !(file_attachments.empty? && item_attachments.empty? && inline_attachments.empty?) end - private - def init_defaults! self.subject ||= nil self.body ||= nil @@ -42,26 +39,26 @@ def to_ews_basic ews_opts[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') if saved_item_folder_id - if saved_item_folder_id.kind_of?(Hash) - ews_opts[:saved_item_folder_id] = saved_item_folder_id - else - ews_opts[:saved_item_folder_id] = {id: saved_item_folder_id} - end + ews_opts[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end end msg = {} msg[:subject] = subject if subject - msg[:body] = {text: body, body_type: body_type} if body + msg[:body] = { text: body, body_type: body_type } if body msg[:importance] = importance if importance - to_r = to_recipients.collect{|r| {mailbox: {email_address: r}}} + to_r = to_recipients.collect { |r| { mailbox: { email_address: r } } } msg[:to_recipients] = to_r unless to_r.empty? - cc_r = cc_recipients.collect{|r| {mailbox: {email_address: r}}} + cc_r = cc_recipients.collect { |r| { mailbox: { email_address: r } } } msg[:cc_recipients] = cc_r unless cc_r.empty? - bcc_r = bcc_recipients.collect{|r| {mailbox: {email_address: r}}} + bcc_r = bcc_recipients.collect { |r| { mailbox: { email_address: r } } } msg[:bcc_recipients] = bcc_r unless bcc_r.empty? msg[:is_read] = is_read @@ -70,7 +67,6 @@ def to_ews_basic [ews_opts, msg] end - end end end diff --git a/lib/ews/templates/reply_to_item.rb b/lib/ews/templates/reply_to_item.rb index 2b6d67de..7c671fd5 100644 --- a/lib/ews/templates/reply_to_item.rb +++ b/lib/ews/templates/reply_to_item.rb @@ -1,25 +1,22 @@ module Viewpoint::EWS module Template class ReplyToItem < Message - # Format this object for EWS backend consumption. def to_ews ews_opts, msg = to_ews_basic msg[:reference_item_id] = reference_item_id - msg[:new_body_content] = {text: new_body_content, body_type: new_body_type} - ews_opts.merge({items: [{ews_type => msg}]}) + msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } + ews_opts.merge({ items: [{ ews_type => msg }] }) end private - def init_defaults! super self.new_body_content ||= '' self.new_body_type ||= 'Text' self.ews_type = :reply_to_item end - end end end diff --git a/lib/ews/templates/task.rb b/lib/ews/templates/task.rb index 2ed3cad8..ff10abff 100644 --- a/lib/ews/templates/task.rb +++ b/lib/ews/templates/task.rb @@ -1,21 +1,19 @@ module Viewpoint::EWS module Template - # Template for creating Tasks - # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx - class Task < OpenStruct - + # Template for creating Tasks + # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx + class Task < OpenStruct # Available parameters with the required ordering - PARAMETERS = %w{mime_content item_id parent_folder_id item_class subject sensitivity body attachments - date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend - is_unmodified internet_message_headers date_time_sent date_time_created response_objects - reminder_due_by reminder_is_set reminder_minutes_before_start display_cc display_to - has_attachments extended_property culture actual_work assigned_time billing_information - change_count companies complete_date contacts delegation_state delegator due_date - is_assignment_editable is_complete is_recurring is_team_task mileage owner percent_complete - recurrence start_date status status_description total_work effective_rights last_modified_name - last_modified_time is_associated web_client_read_form_query_string - web_client_edit_form_query_string conversation_id unique_body - }.map(&:to_sym).freeze + PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments + date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend + is_unmodified internet_message_headers date_time_sent date_time_created response_objects + reminder_due_by reminder_is_set reminder_minutes_before_start display_cc display_to + has_attachments extended_property culture actual_work assigned_time billing_information + change_count companies complete_date contacts delegation_state delegator due_date + is_assignment_editable is_complete is_recurring is_team_task mileage owner percent_complete + recurrence start_date status status_description total_work effective_rights last_modified_name + last_modified_time is_associated web_client_read_form_query_string + web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze # Returns a new Task template def initialize(opts = {}) @@ -27,15 +25,15 @@ def initialize(opts = {}) def to_ews_create structure = {} - if self.saved_item_folder_id - if self.saved_item_folder_id.kind_of?(Hash) - structure[:saved_item_folder_id] = saved_item_folder_id - else - structure[:saved_item_folder_id] = {id: saved_item_folder_id} - end + if saved_item_folder_id + structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end end - structure[:items] = [{task: to_ews_item}] + structure[:items] = [{ task: to_ews_item }] structure end @@ -46,29 +44,27 @@ def to_ews_create def to_ews_item item_parameters = {} PARAMETERS.each do |key| - if !(value = self.send(key)).nil? - - # Convert non duplicable values to String - case value - when NilClass, FalseClass, TrueClass, Symbol, Numeric - value = value.to_s - end + next if (value = send(key)).nil? - # Convert attributes - case key - when :start_date, :due_date - item_parameters[key] = {text: value.respond_to?(:iso8601) ? value.iso8601 : value} - when :body - item_parameters[key] = {body_type: self.body_type || 'Text', text: value.to_s} - else - item_parameters[key] = value - end + # Convert non duplicable values to String + case value + when NilClass, FalseClass, TrueClass, Symbol, Numeric + value = value.to_s end + + # Convert attributes + item_parameters[key] = case key + when :start_date, :due_date + { text: value.respond_to?(:iso8601) ? value.iso8601 : value } + when :body + { body_type: body_type || 'Text', text: value.to_s } + else + value + end end item_parameters end - end end end diff --git a/lib/ews/types.rb b/lib/ews/types.rb index 7c143ca8..71197e9b 100644 --- a/lib/ews/types.rb +++ b/lib/ews/types.rb @@ -3,10 +3,10 @@ module Types include Viewpoint::StringUtils KEY_PATHS = { - extended_properties: [:extended_property], + extended_properties: [:extended_property] } KEY_TYPES = { - extended_properties: :build_extended_properties, + extended_properties: :build_extended_properties } KEY_ALIAS = {} @@ -23,14 +23,14 @@ def initialize(ews, ews_item) def method_missing(method_sym, *arguments, &block) if method_keys.include?(method_sym) - type_convert( method_sym, resolve_method(method_sym) ) + type_convert(method_sym, resolve_method(method_sym)) else super end end def to_s - "#{self.class.name}: EWS METHODS: #{self.ews_methods.sort.join(', ')}" + "#{self.class.name}: EWS METHODS: #{ews_methods.sort.join(', ')}" end def frozen? @@ -59,21 +59,17 @@ def auto_deepen? end def deepen! - if shallow? - self.get_all_properties! - @shallow = false - true - end + return unless shallow? + + get_all_properties! + @shallow = false + true end - alias_method :enlighten!, :deepen! + alias enlighten! deepen! # @see http://www.ruby-doc.org/core/classes/Object.html#M000333 def respond_to?(method_sym, include_private = false) - if method_keys.include?(method_sym) - true - else - super - end + method_keys.include?(method_sym) || super end def methods(include_super = true) @@ -105,47 +101,33 @@ def key_alias end def class_by_name(cname) - if(cname.instance_of? Symbol) - cname = camel_case(cname) - end + cname = camel_case(cname) if cname.instance_of? Symbol Viewpoint::EWS::Types.const_get(cname) end - def type_convert(key,str) - begin - key = key_alias[key] || key - if key_types[key] - key_types[key].is_a?(Symbol) ? method(key_types[key]).call(str) : key_types[key].call(str) - else - str - end - rescue - nil + def type_convert(key, str) + key = key_alias[key] || key + if key_types[key] + key_types[key].is_a?(Symbol) ? method(key_types[key]).call(str) : key_types[key].call(str) + else + str end + rescue StandardError + nil end def resolve_method(method_sym) - begin - resolve_key_path(@ews_item, method_path(method_sym)) - rescue - if shallow? - if frozen? - raise EwsFrozenObjectError, "Could not resolve :#{method_sym} on frozen object." - elsif auto_deepen? - enlighten! - retry - else - if !auto_deepen? - if ews.no_auto_deepen_behavior == :raise - raise EwsMinimalObjectError, "Could not resolve :#{method_sym}. #auto_deepen set to false" - else - nil - end - else - end - end - else - nil + resolve_key_path(@ews_item, method_path(method_sym)) + rescue StandardError + if shallow? + if frozen? + raise EwsFrozenObjectError, "Could not resolve :#{method_sym} on frozen object." + elsif auto_deepen? + enlighten! + retry + elsif !auto_deepen? && (ews.no_auto_deepen_behavior == :raise) + raise EwsMinimalObjectError, "Could not resolve :#{method_sym}. #auto_deepen set to false" + end end end @@ -153,7 +135,8 @@ def resolve_method(method_sym) def resolve_key_path(hsh, path) k = path.first return hsh[k] if path.length == 1 - resolve_key_path(hsh[k],path[1..-1]) + + resolve_key_path(hsh[k], path[1..-1]) end def method_keys @@ -172,23 +155,22 @@ def build_extended_properties(eprops) # probably needs fixing via a dedicated response parser eprops.each do |e| if e.size == 1 - e[:elems].each_cons(2) do |k,v| + e[:elems].each_cons(2) do |k, v| key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym val = v[:value][:text] - h.store(key,val) + h.store(key, val) end elsif e.size == 2 - e[1].each_cons(2) do |k,v| + e[1].each_cons(2) do |k, v| key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym val = v[:value][:text] - h.store(key,val) + h.store(key, val) end else - raise EwsMinimalObjectError, "Not prepared to deal with elements greater than 2" + raise EwsMinimalObjectError, 'Not prepared to deal with elements greater than 2' end end h end - end end diff --git a/lib/ews/types/attachment.rb b/lib/ews/types/attachment.rb index 87e4bc08..145e7efd 100644 --- a/lib/ews/types/attachment.rb +++ b/lib/ews/types/attachment.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types # A generic Attachment. This class should not be instantiated directly. You @@ -25,25 +23,25 @@ class Attachment include Viewpoint::EWS::Types::Item ATTACH_KEY_PATHS = { - :id => [:attachment_id, :attribs, :id], - :parent_item_id => [:attachment_id, :attribs, :root_item_id], - :parent_change_key => [:attachment_id, :attribs, :root_item_change_key], - :name => [:name, :text], - :content_type => [:content_type, :text], - :content_id => [:content_id], - :size => [:size, :text], - :last_modified_time => [:last_modified_time, :text], - :is_inline? => [:is_inline, :text], + id: %i[attachment_id attribs id], + parent_item_id: %i[attachment_id attribs root_item_id], + parent_change_key: %i[attachment_id attribs root_item_change_key], + name: %i[name text], + content_type: %i[content_type text], + content_id: [:content_id], + size: %i[size text], + last_modified_time: %i[last_modified_time text], + is_inline?: %i[is_inline text] } ATTACH_KEY_TYPES = { - is_inline?: ->(str){str.downcase == 'true'}, - last_modified_type: ->(str){DateTime.parse(str)}, - size: ->(str){str.to_i}, - content_id: :fix_content_id, + is_inline?: ->(str) { str.downcase == 'true' }, + last_modified_type: ->(str) { DateTime.parse(str) }, + size: ->(str) { str.to_i }, + content_id: :fix_content_id } - ATTACH_KEY_ALIAS = { } + ATTACH_KEY_ALIAS = {} # @param [Hash] attachment The attachment ews_item def initialize(item, attachment) @@ -51,10 +49,8 @@ def initialize(item, attachment) super(item.ews, attachment) end - private - def key_paths @key_paths ||= ATTACH_KEY_PATHS end @@ -72,6 +68,5 @@ def key_alias def fix_content_id(content_id) content_id.is_a?(Array) ? content_id.last[:text] : content_id[:text] end - end end diff --git a/lib/ews/types/attendee.rb b/lib/ews/types/attendee.rb index 33d833d9..80b7843a 100644 --- a/lib/ews/types/attendee.rb +++ b/lib/ews/types/attendee.rb @@ -1,27 +1,23 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - # This represents a Mailbox object in the Exchange data store # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs # @todo Design a Class method that resolves to an Array of MailboxUsers class Attendee < MailboxUser end # Attendee - end # Viewpoint::EWS::Types diff --git a/lib/ews/types/calendar_folder.rb b/lib/ews/types/calendar_folder.rb index a3b80e26..775c381e 100644 --- a/lib/ews/types/calendar_folder.rb +++ b/lib/ews/types/calendar_folder.rb @@ -7,24 +7,18 @@ class CalendarFolder # Fetch items between a given time period # @param [DateTime] start_date the time to start fetching Items from # @param [DateTime] end_date the time to stop fetching Items from - def items_between(start_date, end_date, opts={}) + def items_between(start_date, end_date, _opts = {}) items do |obj| - obj.restriction = { :and => - [ - {:is_greater_than_or_equal_to => - [ - {:field_uRI => {:field_uRI=>'calendar:Start'}}, - {:field_uRI_or_constant=>{:constant => {:value =>start_date}}} - ] - }, - {:is_less_than_or_equal_to => - [ - {:field_uRI => {:field_uRI=>'calendar:End'}}, - {:field_uRI_or_constant=>{:constant => {:value =>end_date}}} - ] - } - ] - } + obj.restriction = { and: [ + { is_greater_than_or_equal_to: [ + { field_uRI: { field_uRI: 'calendar:Start' } }, + { field_uRI_or_constant: { constant: { value: start_date } } } + ] }, + { is_less_than_or_equal_to: [ + { field_uRI: { field_uRI: 'calendar:End' } }, + { field_uRI_or_constant: { constant: { value: end_date } } } + ] } + ] } end end @@ -35,10 +29,10 @@ def items_between(start_date, end_date, opts={}) # @param [DateTime] end_date the time to stop fetching Items from # @param opts [Hash] # @option opts :max_entries_returned [Integer] the maximum number of entries to return - def items_between_calendar_view(start_date, end_date, opts={}) - view_opts = {:start_date => start_date, :end_date => end_date} + def items_between_calendar_view(start_date, end_date, opts = {}) + view_opts = { start_date: start_date, end_date: end_date } view_opts[:max_entries_returned] = opts.delete(:max_entries_returned) if opts[:max_entries_returned] - items(opts.merge(:calendar_view => view_opts)) + items(opts.merge(calendar_view: view_opts)) end # Creates a new appointment @@ -50,18 +44,16 @@ def items_between_calendar_view(start_date, end_date, opts={}) # @see Template::CalendarItem def create_item(attributes, to_ews_create_opts = {}) template = Viewpoint::EWS::Template::CalendarItem.new attributes - template.saved_item_folder_id = {id: self.id, change_key: self.change_key} + template.saved_item_folder_id = { id: id, change_key: change_key } rm = ews.create_item(template.to_ews_create(to_ews_create_opts)).response_messages.first if rm && rm.success? CalendarItem.new ews, rm.items.first[:calendar_item][:elems].first else - if rm - raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" - else - raise EwsCreateItemError, "Could not create item in folder." - end + raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm + + raise EwsCreateItemError, 'Could not create item in folder.' + end end - end end diff --git a/lib/ews/types/calendar_item.rb b/lib/ews/types/calendar_item.rb index 5369441e..41aff1d6 100644 --- a/lib/ews/types/calendar_item.rb +++ b/lib/ews/types/calendar_item.rb @@ -6,32 +6,32 @@ class CalendarItem include Viewpoint::StringUtils CALENDAR_ITEM_KEY_PATHS = { - recurring?: [:is_recurring, :text], - meeting?: [:is_meeting, :text], - cancelled?: [:is_cancelled, :text], - duration: [:duration, :text], - time_zone: [:time_zone, :text], - start: [:start, :text], - end: [:end, :text], - location: [:location, :text], - all_day?: [:is_all_day_event, :text], - legacy_free_busy_status: [:legacy_free_busy_status, :text], - my_response_type: [:my_response_type, :text], + recurring?: %i[is_recurring text], + meeting?: %i[is_meeting text], + cancelled?: %i[is_cancelled text], + duration: %i[duration text], + time_zone: %i[time_zone text], + start: %i[start text], + end: %i[end text], + location: %i[location text], + all_day?: %i[is_all_day_event text], + legacy_free_busy_status: %i[legacy_free_busy_status text], + my_response_type: %i[my_response_type text], organizer: [:organizer, :elems, 0, :mailbox, :elems], - optional_attendees: [:optional_attendees, :elems ], - required_attendees: [:required_attendees, :elems ], - recurrence: [:recurrence, :elems ], - deleted_occurrences: [:deleted_occurrences, :elems ], - modified_occurrences: [:modified_occurrences, :elems ] - } + optional_attendees: %i[optional_attendees elems], + required_attendees: %i[required_attendees elems], + recurrence: %i[recurrence elems], + deleted_occurrences: %i[deleted_occurrences elems], + modified_occurrences: %i[modified_occurrences elems] + } CALENDAR_ITEM_KEY_TYPES = { - start: ->(str){DateTime.parse(str)}, - end: ->(str){DateTime.parse(str)}, - recurring?: ->(str){str.downcase == 'true'}, - meeting?: ->(str){str.downcase == 'true'}, - cancelled?: ->(str){str.downcase == 'true'}, - all_day?: ->(str){str.downcase == 'true'}, + start: ->(str) { DateTime.parse(str) }, + end: ->(str) { DateTime.parse(str) }, + recurring?: ->(str) { str.downcase == 'true' }, + meeting?: ->(str) { str.downcase == 'true' }, + cancelled?: ->(str) { str.downcase == 'true' }, + all_day?: ->(str) { str.downcase == 'true' }, organizer: :build_mailbox_user, optional_attendees: :build_attendees_users, required_attendees: :build_attendees_users, @@ -48,7 +48,7 @@ class CalendarItem # Default is 'SendOnlyToAll' # @return [Boolean] Whether or not the calendar item was deleted def delete!(deltype = :hard, cancel_type = 'SendOnlyToAll', opts = {}) - opts = opts.merge(:send_meeting_cancellations => cancel_type) + opts = opts.merge(send_meeting_cancellations: cancel_type) super(deltype, opts) end @@ -70,65 +70,62 @@ def update_item!(updates, options = {}) item_updates = [] updates.each do |attribute, value| item_field = FIELD_URIS[attribute][:text] if FIELD_URIS.include? attribute - field = {field_uRI: {field_uRI: item_field}} + field = { field_uRI: { field_uRI: item_field } } if value.nil? && item_field # Build DeleteItemField Change - item_updates << {delete_item_field: field} + item_updates << { delete_item_field: field } elsif item_field # Build SetItemField Change item = Viewpoint::EWS::Template::CalendarItem.new(attribute => value) # Remap attributes because ews_builder #dispatch_field_item! uses #build_xml! - item_attributes = item.to_ews_item.map do |name, value| + item_attributes = item.to_ews_item.map { |name, value| if value.is_a? String - {name => {text: value}} + { name => { text: value } } elsif value.is_a? Hash - node = {name => {}} + node = { name => {} } value.each do |attrib_key, attrib_value| attrib_key = camel_case(attrib_key) unless attrib_key == :text node[name][attrib_key] = attrib_value end node else - {name => value} + { name => value } end - end + } - item_updates << {set_item_field: field.merge(calendar_item: {sub_elements: item_attributes})} + item_updates << { set_item_field: field.merge(calendar_item: { sub_elements: item_attributes }) } else # Ignore unknown attribute end end - if item_updates.any? - data = {} - data[:conflict_resolution] = options[:conflict_resolution] || 'AutoResolve' - data[:send_meeting_invitations_or_cancellations] = options[:send_meeting_invitations_or_cancellations] || 'SendToNone' - data[:item_changes] = [{item_id: self.item_id, updates: item_updates}] - rm = ews.update_item(data).response_messages.first - if rm && rm.success? - self.get_all_properties! - self - else - if rm - raise EwsCreateItemError, "Could not update calendar item. #{rm.code}: #{rm.message_text}" - else - raise EwsCreateItemError, "Could not update calendar item." - end - end - end + return unless item_updates.any? + + data = {} + data[:conflict_resolution] = options[:conflict_resolution] || 'AutoResolve' + data[:send_meeting_invitations_or_cancellations] = + options[:send_meeting_invitations_or_cancellations] || 'SendToNone' + data[:item_changes] = [{ item_id: item_id, updates: item_updates }] + rm = ews.update_item(data).response_messages.first + if rm && rm.success? + get_all_properties! + self + else + raise EwsCreateItemError, "Could not update calendar item. #{rm.code}: #{rm.message_text}" if rm + + raise EwsCreateItemError, 'Could not update calendar item.' + end end def duration_in_seconds iso8601_duration_to_seconds(duration) end - private - def key_paths super.merge(CALENDAR_ITEM_KEY_PATHS) end @@ -140,7 +137,5 @@ def key_types def key_alias super.merge(CALENDAR_ITEM_KEY_ALIAS) end - - end end diff --git a/lib/ews/types/contacts_folder.rb b/lib/ews/types/contacts_folder.rb index 548f8ce8..76233d3b 100644 --- a/lib/ews/types/contacts_folder.rb +++ b/lib/ews/types/contacts_folder.rb @@ -3,6 +3,5 @@ class ContactsFolder include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::GenericFolder - end end diff --git a/lib/ews/types/copied_event.rb b/lib/ews/types/copied_event.rb index 3571d1b5..a9ce4ac1 100644 --- a/lib/ews/types/copied_event.rb +++ b/lib/ews/types/copied_event.rb @@ -1,40 +1,33 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class CopiedEvent < Event - COPIED_EVENT_KEY_PATHS = { - :old_item_id => [:old_item_id, :attribs], - :old_folder_id => [:old_folder_id, :attribs], - :old_parent_folder_id => [:old_parent_folder_id, :attribs], - } - - COPIED_EVENT_KEY_TYPES = { + old_item_id: %i[old_item_id attribs], + old_folder_id: %i[old_folder_id attribs], + old_parent_folder_id: %i[old_parent_folder_id attribs] } - COPIED_EVENT_KEY_ALIAS = { } + COPIED_EVENT_KEY_TYPES = {} + COPIED_EVENT_KEY_ALIAS = {} private - def key_paths @key_paths ||= super.merge COPIED_EVENT_KEY_PATHS end @@ -46,6 +39,5 @@ def key_types def key_alias @key_alias ||= super.merge COPIED_EVENT_KEY_ALIAS end - end end diff --git a/lib/ews/types/created_event.rb b/lib/ews/types/created_event.rb index 7039c5ab..16501668 100644 --- a/lib/ews/types/created_event.rb +++ b/lib/ews/types/created_event.rb @@ -1,24 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class CreatedEvent < Event - end end diff --git a/lib/ews/types/deleted_event.rb b/lib/ews/types/deleted_event.rb index 24d3e601..e20c5fbc 100644 --- a/lib/ews/types/deleted_event.rb +++ b/lib/ews/types/deleted_event.rb @@ -1,24 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class DeletedEvent < Event - end end diff --git a/lib/ews/types/event.rb b/lib/ews/types/event.rb index e83bf339..f92040bb 100644 --- a/lib/ews/types/event.rb +++ b/lib/ews/types/event.rb @@ -1,51 +1,46 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class Event include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::Item EVENT_KEY_PATHS = { - :watermark => [:watermark, :text], - :timestamp => [:time_stamp, :text], - :item_id => [:item_id, :attribs], - :folder_id => [:folder_id, :attribs], - :parent_folder_id => [:parent_folder_id, :attribs], + watermark: %i[watermark text], + timestamp: %i[time_stamp text], + item_id: %i[item_id attribs], + folder_id: %i[folder_id attribs], + parent_folder_id: %i[parent_folder_id attribs] } EVENT_KEY_TYPES = { - :timestamp => ->(ts){ DateTime.iso8601(ts) } + timestamp: ->(ts) { DateTime.iso8601(ts) } } - EVENT_KEY_ALIAS = { } + EVENT_KEY_ALIAS = {} def initialize(ews, event) @ews = ews super(ews, event) end - private - def key_paths @key_paths ||= EVENT_KEY_PATHS end @@ -57,6 +52,5 @@ def key_types def key_alias @key_alias ||= EVENT_KEY_ALIAS end - end end diff --git a/lib/ews/types/export_items_response_message.rb b/lib/ews/types/export_items_response_message.rb index 08b0685d..14ec17cf 100644 --- a/lib/ews/types/export_items_response_message.rb +++ b/lib/ews/types/export_items_response_message.rb @@ -1,19 +1,18 @@ module Viewpoint::EWS::Types - class ExportItemsResponseMessage include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::Item BULK_KEY_PATHS = { - :id => [:item_id, :attribs, :id], - :change_key => [:item_id, :attribs, :change_key], - :data => [:data, :text] + id: %i[item_id attribs id], + change_key: %i[item_id attribs change_key], + data: %i[data text] } - BULK_KEY_TYPES = { } + BULK_KEY_TYPES = {} - BULK_KEY_ALIAS = { } + BULK_KEY_ALIAS = {} def initialize(ews, bulk_item) super(ews, bulk_item) @@ -33,7 +32,6 @@ def data @item[:data][:text] end - private def key_paths @@ -47,6 +45,5 @@ def key_types def key_alias @key_alias ||= BULK_KEY_ALIAS end - end -end \ No newline at end of file +end diff --git a/lib/ews/types/file_attachment.rb b/lib/ews/types/file_attachment.rb index cee0d297..d4d552ae 100644 --- a/lib/ews/types/file_attachment.rb +++ b/lib/ews/types/file_attachment.rb @@ -1,45 +1,41 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types class FileAttachment < Attachment - FILE_ATTACH_KEY_PATHS = { - :is_contact_photo? => [:is_contact_photo, :text], - :content => [:content, :text], + is_contact_photo?: %i[is_contact_photo text], + content: %i[content text] } FILE_ATTACH_KEY_TYPES = { - is_contact_photo?: ->(str){str.downcase == 'true'}, + is_contact_photo?: ->(str) { str.downcase == 'true' } } FILE_ATTACH_KEY_ALIAS = { - :file_name => :name, + file_name: :name } def get_all_properties! - resp = ews.get_attachment attachment_ids: [self.id] + resp = ews.get_attachment attachment_ids: [id] @ews_item.merge!(parse_response(resp)) end private - def key_paths super.merge(FILE_ATTACH_KEY_PATHS) end @@ -53,13 +49,9 @@ def key_alias end def parse_response(resp) - if(resp.status == 'Success') - resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge) - else - raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" - end - end + raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge) + end end end - diff --git a/lib/ews/types/folder.rb b/lib/ews/types/folder.rb index 18cd0a4f..3ab267ca 100644 --- a/lib/ews/types/folder.rb +++ b/lib/ews/types/folder.rb @@ -5,43 +5,38 @@ class Folder include Viewpoint::EWS::Types::GenericFolder FOLDER_KEY_PATHS = { - :unread_count => [:unread_count, :text], + unread_count: %i[unread_count text] } FOLDER_KEY_TYPES = { - :unread_count => ->(str){str.to_i}, + unread_count: ->(str) { str.to_i } } FOLDER_KEY_ALIAS = {} - alias :messages :items + alias messages items def unread_messages - self.items read_unread_restriction + items read_unread_restriction end def read_messages - self.items read_unread_restriction(true) + items read_unread_restriction(true) end def messages_with_attachments - opts = {:restriction => - {:is_equal_to => [ - {:field_uRI => {:field_uRI=>'item:HasAttachments'}}, - {:field_uRI_or_constant => {:constant => {:value=> true}}} - ]} - } - self.items opts + opts = { restriction: { is_equal_to: [ + { field_uRI: { field_uRI: 'item:HasAttachments' } }, + { field_uRI_or_constant: { constant: { value: true } } } + ] } } + items opts end private - def read_unread_restriction(read = false) - {:restriction => - {:is_equal_to => [ - {:field_uRI => {:field_uRI=>'message:IsRead'}}, - {:field_uRI_or_constant => {:constant => {:value=> read}}} - ]} - } + { restriction: { is_equal_to: [ + { field_uRI: { field_uRI: 'message:IsRead' } }, + { field_uRI_or_constant: { constant: { value: read } } } + ] } } end def key_paths @@ -55,6 +50,5 @@ def key_types def key_alias @key_alias ||= super.merge(FOLDER_KEY_ALIAS) end - end end diff --git a/lib/ews/types/free_busy_changed_event.rb b/lib/ews/types/free_busy_changed_event.rb index 3b1077b5..eb3d095a 100644 --- a/lib/ews/types/free_busy_changed_event.rb +++ b/lib/ews/types/free_busy_changed_event.rb @@ -1,24 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class FreeBusyChangedEvent < Event - end end diff --git a/lib/ews/types/generic_folder.rb b/lib/ews/types/generic_folder.rb index b3a85aa9..96bf6df0 100644 --- a/lib/ews/types/generic_folder.rb +++ b/lib/ews/types/generic_folder.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'ews/item_accessors' @@ -26,25 +24,25 @@ module GenericFolder include Viewpoint::StringUtils GFOLDER_KEY_PATHS = { - :folder_id => [:folder_id, :attribs], - :id => [:folder_id, :attribs, :id], - :change_key => [:folder_id, :attribs, :change_key], - :parent_folder_id => [:parent_folder_id, :attribs, :id], - :parent_folder_change_key => [:parent_folder_id, :attribs, :change_key], - :folder_class => [:folder_class, :text], - :total_count => [:total_count, :text], - :child_folder_count => [:child_folder_count, :text], - :display_name => [:display_name, :text], + folder_id: %i[folder_id attribs], + id: %i[folder_id attribs id], + change_key: %i[folder_id attribs change_key], + parent_folder_id: %i[parent_folder_id attribs id], + parent_folder_change_key: %i[parent_folder_id attribs change_key], + folder_class: %i[folder_class text], + total_count: %i[total_count text], + child_folder_count: %i[child_folder_count text], + display_name: %i[display_name text] } GFOLDER_KEY_TYPES = { - :total_count => ->(str){str.to_i}, - :child_folder_count => ->(str){str.to_i}, + total_count: ->(str) { str.to_i }, + child_folder_count: ->(str) { str.to_i } } GFOLDER_KEY_ALIAS = { - :name => :display_name, - :ckey => :change_key, + name: :display_name, + ckey: :change_key } attr_accessor :subscription_id, :watermark, :sync_state @@ -60,15 +58,11 @@ def initialize(ews, ews_item) def delete! opts = { - :folder_ids => [:id => id], - :delete_type => 'HardDelete' + folder_ids: [{ id: id }], + delete_type: 'HardDelete' } resp = @ews.delete_folder(opts) - if resp.success? - true - else - raise EwsError, "Could not delete folder. #{resp.code}: #{resp.message}" - end + resp.success? || raise(EwsError, "Could not delete folder. #{resp.code}: #{resp.message}") end def items(opts = {}) @@ -84,43 +78,33 @@ def items(opts = {}) # @param [DateTime] date_time the time to fetch Items since. def items_since(date_time, opts = {}) opts = opts.clone - unless date_time.kind_of?(Date) - raise EwsBadArgumentError, "First argument must be a Date or DateTime" - end - restr = {:restriction => - {:is_greater_than_or_equal_to => - [{:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, - {:field_uRI_or_constant =>{:constant => {:value=>date_time.to_datetime}}}] - }} - items(opts.merge(restr)) + raise EwsBadArgumentError, 'First argument must be a Date or DateTime' unless date_time.is_a?(Date) + + restr = { restriction: { is_greater_than_or_equal_to: [{ field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: date_time.to_datetime } } }] } } + items(opts.merge(restr)) end # Fetch only items from today (since midnight) - def todays_items(opts = {}) + def todays_items(_opts = {}) items_since(Date.today) end # Fetch items between a given time period # @param [DateTime] start_date the time to start fetching Items from # @param [DateTime] end_date the time to stop fetching Items from - def items_between(start_date, end_date, opts={}) + def items_between(start_date, end_date, _opts = {}) items do |obj| - obj.restriction = { :and => - [ - {:is_greater_than_or_equal_to => - [ - {:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, - {:field_uRI_or_constant=>{:constant => {:value =>start_date}}} - ] - }, - {:is_less_than_or_equal_to => - [ - {:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, - {:field_uRI_or_constant=>{:constant => {:value =>end_date}}} - ] - } - ] - } + obj.restriction = { and: [ + { is_greater_than_or_equal_to: [ + { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: start_date } } } + ] }, + { is_less_than_or_equal_to: [ + { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: end_date } } } + ] } + ] } end end @@ -131,30 +115,28 @@ def items_between(start_date, end_date, opts={}) # the subject. This is optional. def search_by_subject(match_str, exclude_str = nil) items do |obj| - match = {:contains => { - :containment_mode => 'Substring', - :containment_comparison => 'IgnoreCase', - :field_uRI => {:field_uRI=>'item:Subject'}, - :constant => {:value =>match_str} - }} + match = { contains: { + containment_mode: 'Substring', + containment_comparison: 'IgnoreCase', + field_uRI: { field_uRI: 'item:Subject' }, + constant: { value: match_str } + } } unless exclude_str.nil? - excl = {:not => - {:contains => { - :containment_mode => 'Substring', - :containment_comparison => 'IgnoreCase', - :field_uRI => {:field_uRI=>'item:Subject'}, - :constant => {:value =>exclude_str} - }} - } - - match[:and] = [{:contains => match.delete(:contains)}, excl] + excl = { not: { contains: { + containment_mode: 'Substring', + containment_comparison: 'IgnoreCase', + field_uRI: { field_uRI: 'item:Subject' }, + constant: { value: exclude_str } + } } } + + match[:and] = [{ contains: match.delete(:contains) }, excl] end obj.restriction = match end end def get_all_properties! - @ews_item = get_folder(:base_shape => 'AllProperties') + @ews_item = get_folder(base_shape: 'AllProperties') simplify! end @@ -162,13 +144,13 @@ def available_categories opts = { user_config_name: { name: 'CategoryList', - distinguished_folder_id: {id: :calendar} + distinguished_folder_id: { id: :calendar } }, user_config_props: 'XmlData' } - resp = ews.get_user_configuration(opts) - #txt = resp.response_message[:elems][:get_user_configuration_response_message][:elems][1][:user_configuration][:elems][1][:xml_data][:text] - #Base64.decode64 txt + ews.get_user_configuration(opts) + # txt = resp.response_message[:elems][:get_user_configuration_response_message][:elems][1][:user_configuration][:elems][1][:xml_data][:text] + # Base64.decode64 txt end # Syncronize Items in this folder. If this method is issued multiple @@ -183,33 +165,31 @@ def available_categories # For :deleted and :read_flag_change items a simple hash with :id and # :change_key is returned. # See: http://msdn.microsoft.com/en-us/library/aa565609.aspx - def sync_items!(sync_state = nil, sync_amount = 256, sync_all = false, opts = {}) - item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : {:base_shape => :default} + def sync_items!(sync_state = nil, sync_amount = 256, _sync_all = false, opts = {}) + item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : { base_shape: :default } sync_state ||= @sync_state resp = ews.sync_folder_items item_shape: item_shape, - sync_folder_id: self.folder_id, max_changes_returned: sync_amount, sync_state: sync_state + sync_folder_id: folder_id, max_changes_returned: sync_amount, sync_state: sync_state rmsg = resp.response_messages[0] - if rmsg.success? - @synced = rmsg.includes_last_item_in_range? - @sync_state = rmsg.sync_state - rhash = {} - rmsg.changes.each do |c| - ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) - if ctype == :delete || ctype == :read_flag_change - rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs] - else - type = c[ctype][:elems][0].keys.first - item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) - rhash[ctype] << item - end + raise EwsError, "Could not synchronize: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @synced = rmsg.includes_last_item_in_range? + @sync_state = rmsg.sync_state + rhash = {} + rmsg.changes.each do |c| + ctype = c.keys.first + rhash[ctype] = [] unless rhash.has_key?(ctype) + if %i[delete read_flag_change].include?(ctype) + rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs] + else + type = c[ctype][:elems][0].keys.first + item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) + rhash[ctype] << item end - rhash - else - raise EwsError, "Could not synchronize: #{rmsg.code}: #{rmsg.message_text}" end + rhash end def synced? @@ -232,37 +212,32 @@ def subscribe(evtypes = [:all], watermark = nil, timeout = 240) unsubscribe if subscribed? event_types = normalize_event_names(evtypes) - folder = {id: self.id, change_key: self.change_key} + folder = { id: id, change_key: change_key } resp = ews.pull_subscribe_folder(folder, event_types, timeout, watermark) rmsg = resp.response_messages.first - if rmsg.success? - @subscription_id = rmsg.subscription_id - @watermark = rmsg.watermark - true - else - raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" - end + raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @subscription_id = rmsg.subscription_id + @watermark = rmsg.watermark + true end def push_subscribe(url, evtypes = [:all], watermark = nil, status_frequency = nil) - event_types = normalize_event_names(evtypes) - folder = {id: self.id, change_key: self.change_key} + folder = { id: id, change_key: change_key } resp = ews.push_subscribe_folder(folder, event_types, url, status_frequency, watermark) rmsg = resp.response_messages.first - if rmsg.success? - @subscription_id = rmsg.subscription_id - @watermark = rmsg.watermark - true - else - raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" - end + raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @subscription_id = rmsg.subscription_id + @watermark = rmsg.watermark + true end # Check if there is a subscription for this folder. # @return [Boolean] Are we subscribed to this folder? def subscribed? - ( @subscription_id.nil? or @watermark.nil? )? false : true + (@subscription_id.nil? or @watermark.nil?) ? false : true end # Unsubscribe this folder from further Exchange events. @@ -272,40 +247,37 @@ def unsubscribe resp = ews.unsubscribe(@subscription_id) rmsg = resp.response_messages.first - if rmsg.success? - @subscription_id, @watermark = nil, nil - true - else - raise EwsSubscriptionError, "Could not unsubscribe: #{rmsg.code}: #{rmsg.message_text}" - end + raise EwsSubscriptionError, "Could not unsubscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @subscription_id = nil + @watermark = nil + true end # Checks a subscribed folder for events # @return [Array] An array of Event items def get_events - begin - if subscribed? - resp = ews.get_events(@subscription_id, @watermark) - rmsg = resp.response_messages[0] - @watermark = rmsg.new_watermark - # @todo if parms[:more_events] # get more events - rmsg.events.collect{|ev| - type = ev.keys.first - class_by_name(type).new(ews, ev[type]) - } - else - raise EwsSubscriptionError, "Folder <#{self.display_name}> not subscribed to. Issue a Folder#subscribe before checking events." - end - rescue EwsSubscriptionTimeout => e - @subscription_id, @watermark = nil, nil - raise e + if subscribed? + resp = ews.get_events(@subscription_id, @watermark) + rmsg = resp.response_messages[0] + @watermark = rmsg.new_watermark + # @todo if parms[:more_events] # get more events + rmsg.events.collect { |ev| + type = ev.keys.first + class_by_name(type).new(ews, ev[type]) + } + else + raise EwsSubscriptionError, + "Folder <#{display_name}> not subscribed to. Issue a Folder#subscribe before checking events." end + rescue EwsSubscriptionTimeout => e + @subscription_id = nil + @watermark = nil + raise e end - private - def key_paths @key_paths ||= super.merge(GFOLDER_KEY_PATHS) end @@ -319,7 +291,7 @@ def key_alias end def simplify! - @ews_item = @ews_item[:elems].inject({}) do |o,i| + @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| key = i.keys.first if o.has_key?(key) if o[key].is_a?(Array) @@ -330,7 +302,6 @@ def simplify! else o[key] = i[key] end - o end end @@ -349,41 +320,37 @@ def get_folder(opts = {}) def get_folder_args(opts) opts[:base_shape] ||= 'Default' default_args = { - :folder_ids => [{:id => self.id, :change_key => self.change_key}], - :folder_shape => {:base_shape => opts[:base_shape]} + folder_ids: [{ id: id, change_key: change_key }], + folder_shape: { base_shape: opts[:base_shape] } } default_args.merge(opts) end def get_folder_parser(resp) - if(resp.status == 'Success') - f = resp.response_message[:elems][:folders][:elems][0] - f.values.first - else - raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.message}" - end + raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + f = resp.response_message[:elems][:folders][:elems][0] + f.values.first end def items_args(opts) - default_args = { - :parent_folder_ids => [{:id => self.id}], - :traversal => 'Shallow', - :item_shape => {:base_shape => 'Default'} + { + parent_folder_ids: [{ id: id }], + traversal: 'Shallow', + item_shape: { base_shape: 'Default' } }.merge(opts) end def items_parser(resp) rm = resp.response_messages[0] - if(rm.status == 'Success') - items = [] - rm.root_folder.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type], self) - end - items - else - raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" + raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + + items = [] + rm.root_folder.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type], self) end + items end def merge_restrictions!(obj, merge_type = :and) @@ -392,7 +359,7 @@ def merge_restrictions!(obj, merge_type = :and) merge_type => [ obj.opts.delete(:restriction), obj.restriction - ] + ] } elsif !obj.restriction.empty? obj.opts[:restriction] = obj.restriction @@ -400,9 +367,7 @@ def merge_restrictions!(obj, merge_type = :and) end def normalize_event_names(events) - if events.include?(:all) - events = [:copied, :created, :deleted, :modified, :moved, :new_mail, :free_busy_changed] - end + events = %i[copied created deleted modified moved new_mail free_busy_changed] if events.include?(:all) events.collect do |ev| nev = ruby_case(ev) @@ -413,6 +378,5 @@ def normalize_event_names(events) end end end - end end diff --git a/lib/ews/types/item.rb b/lib/ews/types/item.rb index f6016911..e2e439c2 100644 --- a/lib/ews/types/item.rb +++ b/lib/ews/types/item.rb @@ -10,69 +10,72 @@ def self.included(klass) module ClassMethods def init_simple_item(ews, id, change_key = nil, parent = nil) - ews_item = {item_id: {attribs: {id: id, change_key: change_key}}} - self.new ews, ews_item, parent + ews_item = { item_id: { attribs: { id: id, change_key: change_key } } } + new ews, ews_item, parent end end ITEM_KEY_PATHS = { - item_id: [:item_id, :attribs], - id: [:item_id, :attribs, :id], - change_key: [:item_id, :attribs, :change_key], - subject: [:subject, :text], - sensitivity: [:sensitivity, :text], - size: [:size, :text], - date_time_sent: [:date_time_sent, :text], - date_time_created: [:date_time_created, :text], - last_modified_time: [:last_modified_time, :text], - mime_content: [:mime_content, :text], - has_attachments?:[:has_attachments, :text], - is_associated?: [:is_associated, :text], - is_read?: [:is_read, :text], - is_draft?: [:is_draft, :text], - is_submitted?: [:is_submitted, :text], - conversation_id:[:conversation_id, :attribs, :id], - categories: [:categories, :elems], - internet_message_id:[:internet_message_id, :text], - internet_message_headers:[:internet_message_headers, :elems], - sender: [:sender, :elems, 0, :mailbox, :elems], - from: [:from, :elems, 0, :mailbox, :elems], - to_recipients: [:to_recipients, :elems], - cc_recipients: [:cc_recipients, :elems], - attachments: [:attachments, :elems], - importance: [:importance, :text], - conversation_index: [:conversation_index, :text], - conversation_topic: [:conversation_topic, :text], - body_type: [:body, :attribs, :body_type], - body: [:body, :text] + item_id: %i[item_id attribs], + id: %i[item_id attribs id], + change_key: %i[item_id attribs change_key], + subject: %i[subject text], + sensitivity: %i[sensitivity text], + size: %i[size text], + date_time_sent: %i[date_time_sent text], + date_time_created: %i[date_time_created text], + last_modified_time: %i[last_modified_time text], + mime_content: %i[mime_content text], + has_attachments?: %i[has_attachments text], + is_associated?: %i[is_associated text], + is_read?: %i[is_read text], + is_draft?: %i[is_draft text], + is_submitted?: %i[is_submitted text], + conversation_id: %i[conversation_id attribs id], + categories: %i[categories elems], + internet_message_id: %i[internet_message_id text], + internet_message_headers: %i[internet_message_headers elems], + sender: [:sender, :elems, 0, :mailbox, :elems], + from: [:from, :elems, 0, :mailbox, :elems], + to_recipients: %i[to_recipients elems], + cc_recipients: %i[cc_recipients elems], + attachments: %i[attachments elems], + importance: %i[importance text], + conversation_index: %i[conversation_index text], + conversation_topic: %i[conversation_topic text], + body_type: %i[body attribs body_type], + body: %i[body text] } ITEM_KEY_TYPES = { - size: ->(str){str.to_i}, - date_time_sent: ->(str){DateTime.parse(str)}, - date_time_created: ->(str){DateTime.parse(str)}, - last_modified_time: ->(str){DateTime.parse(str)}, - has_attachments?: ->(str){str.downcase == 'true'}, - is_associated?: ->(str){str.downcase == 'true'}, - is_read?: ->(str){str.downcase == 'true'}, - is_draft?: ->(str){str.downcase == 'true'}, - is_submitted?: ->(str){str.downcase == 'true'}, - categories: ->(obj){obj.collect{|s| s[:string][:text]}}, - internet_message_headers: ->(obj){obj.collect{|h| - {h[:internet_message_header][:attribs][:header_name] => - h[:internet_message_header][:text]} } }, + size: ->(str) { str.to_i }, + date_time_sent: ->(str) { DateTime.parse(str) }, + date_time_created: ->(str) { DateTime.parse(str) }, + last_modified_time: ->(str) { DateTime.parse(str) }, + has_attachments?: ->(str) { str.downcase == 'true' }, + is_associated?: ->(str) { str.downcase == 'true' }, + is_read?: ->(str) { str.downcase == 'true' }, + is_draft?: ->(str) { str.downcase == 'true' }, + is_submitted?: ->(str) { str.downcase == 'true' }, + categories: ->(obj) { obj.collect { |s| s[:string][:text] } }, + internet_message_headers: lambda { |obj| + obj.collect { |h| + { h[:internet_message_header][:attribs][:header_name] => + h[:internet_message_header][:text] } + } + }, sender: :build_mailbox_user, - from: :build_mailbox_user, - to_recipients: :build_mailbox_users, - cc_recipients: :build_mailbox_users, - attachments: :build_attachments, + from: :build_mailbox_user, + to_recipients: :build_mailbox_users, + cc_recipients: :build_mailbox_users, + attachments: :build_attachments } ITEM_KEY_ALIAS = { - :read? => :is_read?, - :draft? => :is_draft?, - :submitted? => :is_submitted?, - :associated? => :is_associated?, + read?: :is_read?, + draft?: :is_draft?, + submitted?: :is_submitted?, + associated?: :is_associated? } attr_reader :ews_item, :parent @@ -99,15 +102,14 @@ def default_body_type=(body_type) def delete!(deltype = :hard, opts = {}) opts = { - :delete_type => delete_type(deltype), - :item_ids => [{:item_id => {:id => id}}] + delete_type: delete_type(deltype), + item_ids: [{ item_id: { id: id } }] }.merge(opts) resp = @ews.delete_item(opts) rmsg = resp.response_messages[0] - unless rmsg.success? - raise EwsError, "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" - end + raise EwsError, "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + true end @@ -135,21 +137,19 @@ def mark_unread! # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) # @return [String] the new Id of the moved item def move!(new_folder) - new_folder = new_folder.id if new_folder.kind_of?(GenericFolder) + new_folder = new_folder.id if new_folder.is_a?(GenericFolder) move_opts = { - :to_folder_id => {:id => new_folder}, - :item_ids => [{:item_id => {:id => self.id}}] + to_folder_id: { id: new_folder }, + item_ids: [{ item_id: { id: id } }] } resp = @ews.move_item(move_opts) rmsg = resp.response_messages[0] - if rmsg.success? - obj = rmsg.items.first - itype = obj.keys.first - obj[itype][:elems][0][:item_id][:attribs][:id] - else - raise EwsError, "Could not move item. #{resp.code}: #{resp.message}" - end + raise EwsError, "Could not move item. #{resp.code}: #{resp.message}" unless rmsg.success? + + obj = rmsg.items.first + itype = obj.keys.first + obj[itype][:elems][0][:item_id][:attribs][:id] end # Copy this item to a new folder @@ -157,21 +157,19 @@ def move!(new_folder) # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) # @return [String] the new Id of the copied item def copy(new_folder) - new_folder = new_folder.id if new_folder.kind_of?(GenericFolder) + new_folder = new_folder.id if new_folder.is_a?(GenericFolder) copy_opts = { - :to_folder_id => {:id => new_folder}, - :item_ids => [{:item_id => {:id => self.id}}] + to_folder_id: { id: new_folder }, + item_ids: [{ item_id: { id: id } }] } resp = @ews.copy_item(copy_opts) rmsg = resp.response_messages[0] - if rmsg.success? - obj = rmsg.items.first - itype = obj.keys.first - obj[itype][:elems][0][:item_id][:attribs][:id] - else - raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}" - end + raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + + obj = rmsg.items.first + itype = obj.keys.first + obj[itype][:elems][0][:item_id][:attribs][:id] end def add_file_attachment(file) @@ -183,8 +181,8 @@ def add_file_attachment(file) def add_item_attachment(other_item, name = nil) ia = OpenStruct.new - ia.name = (name ? name : other_item.subject) - ia.item = {id: other_item.id, change_key: other_item.change_key} + ia.name = (name || other_item.subject) + ia.item = { id: other_item.id, change_key: other_item.change_key } @new_item_attachments << ia end @@ -198,23 +196,21 @@ def add_inline_attachment(file) def submit! if draft? submit_attachments! - resp = ews.send_item(item_ids: [{item_id: {id: self.id, change_key: self.change_key}}]) + resp = ews.send_item(item_ids: [{ item_id: { id: id, change_key: change_key } }]) rm = resp.response_messages[0] - if rm.success? - true - else - raise EwsSendItemError, "#{rm.code}: #{rm.message_text}" - end + rm.success? || raise(EwsSendItemError, "#{rm.code}: #{rm.message_text}") else false end end def submit_attachments! - return false unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?) + unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?) + return false + end opts = { - parent_id: {id: self.id, change_key: self.change_key}, + parent_id: { id: id, change_key: change_key }, files: @new_file_attachments, items: @new_item_attachments, inline_files: @new_inline_attachments @@ -239,26 +235,25 @@ def submit_attachments! def forward(opts = {}) msg = Template::ForwardItem.new opts.clone yield msg if block_given? - msg.reference_item_id = {id: self.id, change_key: self.change_key} + msg.reference_item_id = { id: id, change_key: change_key } dispatch_create_item! msg end def reply_to(opts = {}) msg = Template::ReplyToItem.new opts.clone yield msg if block_given? - msg.reference_item_id = {id: self.id, change_key: self.change_key} + msg.reference_item_id = { id: id, change_key: change_key } dispatch_create_item! msg end def reply_to_all(opts = {}) msg = Template::ReplyToItem.new opts.clone yield msg if block_given? - msg.reference_item_id = {id: self.id, change_key: self.change_key} + msg.reference_item_id = { id: id, change_key: change_key } msg.ews_type = :reply_all_to_item dispatch_create_item! msg end - private def key_paths @@ -275,27 +270,25 @@ def key_alias def update_is_read_status(read) field = :is_read - opts = {item_changes: + opts = { item_changes: [ - { item_id: {id: id, change_key: change_key}, + { item_id: { id: id, change_key: change_key }, updates: [ - {set_item_field: {field_uRI: {field_uRI: FIELD_URIS[field][:text]}, - message: {sub_elements: [{field => {text: read}}]}}} - ] - } - ] - } - resp = ews.update_item({conflict_resolution: 'AutoResolve'}.merge(opts)) + { set_item_field: { field_uRI: { field_uRI: FIELD_URIS[field][:text] }, + message: { sub_elements: [{ field => { text: read } }] } } } + ] } + ] } + resp = ews.update_item({ conflict_resolution: 'AutoResolve' }.merge(opts)) rmsg = resp.response_messages[0] - unless rmsg.success? - raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}" - end + raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + true end def simplify! return unless @ews_item.has_key?(:elems) - @ews_item = @ews_item[:elems].inject({}) do |o,i| + + @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| key = i.keys.first if o.has_key?(key) if o[key].is_a?(Array) @@ -306,7 +299,6 @@ def simplify! else o[key] = i[key] end - o end end @@ -325,8 +317,8 @@ def get_item(opts = {}) def get_item_args(opts) opts[:base_shape] ||= 'Default' default_args = { - item_shape: {base_shape: opts[:base_shape]}, - item_ids: [{item_id:{id: id, change_key: change_key}}] + item_shape: { base_shape: opts[:base_shape] }, + item_ids: [{ item_id: { id: id, change_key: change_key } }] } default_args[:item_shape][:body_type] = @body_type if @body_type default_args @@ -334,11 +326,9 @@ def get_item_args(opts) def get_item_parser(resp) rm = resp.response_messages[0] - if(rm.status == 'Success') - rm.items[0].values.first - else - raise EwsError, "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" - end + raise EwsError, "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + + rm.items[0].values.first end # Map a delete type to what EWS expects @@ -353,7 +343,7 @@ def delete_type(type) end def build_deleted_occurrences(occurrences) - occurrences.collect{|a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text]} + occurrences.collect { |a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text] } end def build_modified_occurrences(occurrences) @@ -361,9 +351,9 @@ def build_modified_occurrences(occurrences) occurrences.collect do |a| elems = a[:occurrence][:elems] - h[DateTime.parse(elems.find{|e| e[:original_start]}[:original_start][:text])] = { - start: elems.find{|e| e[:start]}[:start][:text], - end: elems.find{|e| e[:end]}[:end][:text] + h[DateTime.parse(elems.find { |e| e[:original_start] }[:original_start][:text])] = { + start: elems.find { |e| e[:start] }[:start][:text], + end: elems.find { |e| e[:end] }[:end][:text] } end end @@ -375,20 +365,23 @@ def build_mailbox_user(mbox_ews) def build_mailbox_users(users) return [] if users.nil? - users.collect{|u| build_mailbox_user(u[:mailbox][:elems])} + + users.collect { |u| build_mailbox_user(u[:mailbox][:elems]) } end def build_attendees_users(users) return [] if users.nil? - users.collect do |u| + + users.collect { |u| u[:attendee][:elems].collect do |a| build_mailbox_user(a[:mailbox][:elems]) if a[:mailbox] end - end.flatten.compact + }.flatten.compact end def build_attachments(attachments) return [] if attachments.nil? + attachments.collect do |att| key = att.keys.first class_by_name(key).new(self, att[key]) @@ -408,7 +401,8 @@ def dispatch_create_item!(msg) msg.draft = true resp = validate_created_item(ews.create_item(msg.to_ews)) msg.file_attachments.each do |f| - next unless f.kind_of?(File) + next unless f.is_a?(File) + resp.add_file_attachment(f) end if draft @@ -431,17 +425,14 @@ def dispatch_create_item!(msg) def validate_created_item(response) msg = response.response_messages[0] - if(msg.status == 'Success') - msg.items.empty? ? true : parse_created_item(msg.items.first) - else - raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}" - end + raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}" unless msg.status == 'Success' + + msg.items.empty? || parse_created_item(msg.items.first) end def parse_created_item(msg) mtype = msg.keys.first - message = class_by_name(mtype).new(ews, msg[mtype]) + class_by_name(mtype).new(ews, msg[mtype]) end - end end diff --git a/lib/ews/types/item_attachment.rb b/lib/ews/types/item_attachment.rb index 1b1bd325..f71a20a1 100644 --- a/lib/ews/types/item_attachment.rb +++ b/lib/ews/types/item_attachment.rb @@ -1,24 +1,21 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types class ItemAttachment < Attachment - ITEM_ATTACH_KEY_PATHS = { item: [:item], message: [:message], @@ -42,10 +39,10 @@ class ItemAttachment < Attachment meeting_cancellation: :build_meeting_cancellation } - ITEM_ATTACH_KEY_ALIAS = { } + ITEM_ATTACH_KEY_ALIAS = {} def get_all_properties! - resp = ews.get_attachment attachment_ids: [self.id] + resp = ews.get_attachment attachment_ids: [id] @ews_item.merge!(parse_response(resp)) end @@ -53,7 +50,7 @@ def get_all_properties! def self.method_missing(method, *args, &block) if method.to_s =~ /^build_(.+)$/ - class_by_name($1).new(ews, args[0]) + class_by_name(::Regexp.last_match(1)).new(ews, args[0]) else super end @@ -72,13 +69,9 @@ def key_alias end def parse_response(resp) - if(resp.status == 'Success') - resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge) - else - raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" - end - end + raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge) + end end end - diff --git a/lib/ews/types/item_field_uri_map.rb b/lib/ews/types/item_field_uri_map.rb index 140eeb6c..039855e5 100644 --- a/lib/ews/types/item_field_uri_map.rb +++ b/lib/ews/types/item_field_uri_map.rb @@ -1,207 +1,206 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint module EWS module ItemFieldUriMap - - FIELD_URIS= { - :folder_id => {:text => 'folder:FolderId', :writable => true}, - :total_count => {:text => 'folder:TotalCount', :writable => true}, - :child_folder_count => {:text => 'folder:ChildFolderCount', :writable => true}, - :folder_class => {:text => 'folder:FolderClass', :writable => true}, - :search_parameters => {:text => 'folder:SearchParameters', :writable => true}, - :managed_folder_information => {:text => 'folder:ManagedFolderInformation', :writable => true}, - :permission_set => {:text => 'folder:PermissionSet', :writable => true}, - :sharing_effective_rights => {:text => 'folder:SharingEffectiveRights', :writable => true}, - :item_id => {:text => 'item:ItemId', :writable => true}, - :parent_folder_id => {:text => 'item:ParentFolderId', :writable => true}, - :item_class => {:text => 'item:ItemClass', :writable => true}, - :mime_content => {:text => 'item:MimeContent', :writable => true}, - :attachments => {:text => 'item:Attachments', :writable => true}, - :subject => {:text => 'item:Subject', :writable => true}, - :date_time_received => {:text => 'item:DateTimeReceived', :writable => true}, - :in_reply_to => {:text => 'item:InReplyTo', :writable => true}, - :internet_message_headers => {:text => 'item:InternetMessageHeaders', :writable => true}, - :is_associated => {:text => 'item:IsAssociated', :writable => true}, - :is_draft => {:text => 'item:IsDraft', :writable => true}, - :is_from_me => {:text => 'item:IsFromMe', :writable => true}, - :is_resend => {:text => 'item:IsResend', :writable => true}, - :is_submitted => {:text => 'item:IsSubmitted', :writable => true}, - :is_unmodified => {:text => 'item:IsUnmodified', :writable => true}, - :date_time_sent => {:text => 'item:DateTimeSent', :writable => true}, - :date_time_created => {:text => 'item:DateTimeCreated', :writable => true}, - :body => {:text => 'item:Body', :writable => true}, - :response_objects => {:text => 'item:ResponseObjects', :writable => true}, - :sensitivity => {:text => 'item:Sensitivity', :writable => true}, - :reminder_due_by => {:text => 'item:ReminderDueBy', :writable => true}, - :reminder_is_set => {:text => 'item:ReminderIsSet', :writable => true}, - :reminder_minutes_before_start => {:text => 'item:ReminderMinutesBeforeStart', :writable => true}, - :display_to => {:text => 'item:DisplayTo', :writable => true}, - :display_cc => {:text => 'item:DisplayCc', :writable => true}, - :effective_rights => {:text => 'item:EffectiveRights', :writable => true}, - :last_modified_name => {:text => 'item:LastModifiedName', :writable => true}, - :last_modified_time => {:text => 'item:LastModifiedTime', :writable => true}, - :unique_body => {:text => 'item:UniqueBody', :writable => true}, - :web_client_read_form_query_string => {:text => 'item:WebClientReadFormQueryString', :writable => true}, - :web_client_edit_form_query_string => {:text => 'item:WebClientEditFormQueryString', :writable => true}, - :conversation_index => {:text => 'message:ConversationIndex', :writable => true}, - :internet_message_id => {:text => 'message:InternetMessageId', :writable => true}, - :is_read => {:text => 'message:IsRead', :writable => true}, - :is_read_receipt_requested => {:text => 'message:IsReadReceiptRequested', :writable => true}, - :is_delivery_receipt_requested => {:text => 'message:IsDeliveryReceiptRequested', :writable => true}, - :references => {:text => 'message:References', :writable => true}, - :reply_to => {:text => 'message:ReplyTo', :writable => true}, - :from => {:text => 'message:From', :writable => true}, - :sender => {:text => 'message:Sender', :writable => true}, - :to_recipients => {:text => 'message:ToRecipients', :writable => true}, - :cc_recipients => {:text => 'message:CcRecipients', :writable => true}, - :bcc_recipients => {:text => 'message:BccRecipients', :writable => true}, - :associated_calendar_item_id => {:text => 'meeting:AssociatedCalendarItemId', :writable => true}, - :is_delegated => {:text => 'meeting:IsDelegated', :writable => true}, - :is_out_of_date => {:text => 'meeting:IsOutOfDate', :writable => true}, - :has_been_processed => {:text => 'meeting:HasBeenProcessed', :writable => true}, - :response_type => {:text => 'meeting:ResponseType', :writable => true}, - :meeting_request_type => {:text => 'meetingRequest:MeetingRequestType', :writable => true}, - :intended_free_busy_status => {:text => 'meetingRequest:IntendedFreeBusyStatus', :writable => true}, - :start => {:text => 'calendar:Start', :writable => true}, - :end => {:text => 'calendar:End', :writable => true}, - :original_start => {:text => 'calendar:OriginalStart', :writable => true}, - :is_all_day_event => {:text => 'calendar:IsAllDayEvent', :writable => true}, - :legacy_free_busy_status => {:text => 'calendar:LegacyFreeBusyStatus', :writable => true}, - :location => {:text => 'calendar:Location', :writable => true}, - :when => {:text => 'calendar:When', :writable => true}, - :is_meeting => {:text => 'calendar:IsMeeting', :writable => true}, - :is_cancelled => {:text => 'calendar:IsCancelled', :writable => true}, - :meeting_request_was_sent => {:text => 'calendar:MeetingRequestWasSent', :writable => true}, - :is_response_requested => {:text => 'calendar:IsResponseRequested', :writable => true}, - :calendar_item_type => {:text => 'calendar:CalendarItemType', :writable => true}, - :my_response_type => {:text => 'calendar:MyResponseType', :writable => true}, - :organizer => {:text => 'calendar:Organizer', :writable => true}, - :required_attendees => {:text => 'calendar:RequiredAttendees', :writable => true}, - :optional_attendees => {:text => 'calendar:OptionalAttendees', :writable => true}, - :resources => {:text => 'calendar:Resources', :writable => true}, - :conflicting_meeting_count => {:text => 'calendar:ConflictingMeetingCount', :writable => true}, - :adjacent_meeting_count => {:text => 'calendar:AdjacentMeetingCount', :writable => true}, - :conflicting_meetings => {:text => 'calendar:ConflictingMeetings', :writable => true}, - :adjacent_meetings => {:text => 'calendar:AdjacentMeetings', :writable => true}, - :duration => {:text => 'calendar:Duration', :writable => true}, - :time_zone => {:text => 'calendar:TimeZone', :writable => true}, - :appointment_reply_time => {:text => 'calendar:AppointmentReplyTime', :writable => true}, - :appointment_sequence_number => {:text => 'calendar:AppointmentSequenceNumber', :writable => true}, - :appointment_state => {:text => 'calendar:AppointmentState', :writable => true}, - :first_occurrence => {:text => 'calendar:FirstOccurrence', :writable => true}, - :last_occurrence => {:text => 'calendar:LastOccurrence', :writable => true}, - :modified_occurrences => {:text => 'calendar:ModifiedOccurrences', :writable => true}, - :deleted_occurrences => {:text => 'calendar:DeletedOccurrences', :writable => true}, - :meeting_time_zone => {:text => 'calendar:MeetingTimeZone', :writable => true}, - :conference_type => {:text => 'calendar:ConferenceType', :writable => true}, - :allow_new_time_proposal => {:text => 'calendar:AllowNewTimeProposal', :writable => true}, - :is_online_meeting => {:text => 'calendar:IsOnlineMeeting', :writable => true}, - :meeting_workspace_url => {:text => 'calendar:MeetingWorkspaceUrl', :writable => true}, - :net_show_url => {:text => 'calendar:NetShowUrl', :writable => true}, - :u_i_d => {:text => 'calendar:UID', :writable => true}, - :recurrence_id => {:text => 'calendar:RecurrenceId', :writable => true}, - :date_time_stamp => {:text => 'calendar:DateTimeStamp', :writable => true}, - :start_time_zone => {:text => 'calendar:StartTimeZone', :writable => true}, - :end_time_zone => {:text => 'calendar:EndTimeZone', :writable => true}, - :actual_work => {:text => 'task:ActualWork', :writable => true}, - :assigned_time => {:text => 'task:AssignedTime', :writable => true}, - :billing_information => {:text => 'task:BillingInformation', :writable => true}, - :change_count => {:text => 'task:ChangeCount', :writable => true}, - :complete_date => {:text => 'task:CompleteDate', :writable => true}, - :contacts => {:text => 'task:Contacts', :writable => true}, - :delegation_state => {:text => 'task:DelegationState', :writable => true}, - :delegator => {:text => 'task:Delegator', :writable => true}, - :due_date => {:text => 'task:DueDate', :writable => true}, - :is_assignment_editable => {:text => 'task:IsAssignmentEditable', :writable => true}, - :is_complete => {:text => 'task:IsComplete', :writable => true}, - :is_recurring => {:text => 'task:IsRecurring', :writable => true}, - :is_team_task => {:text => 'task:IsTeamTask', :writable => true}, - :owner => {:text => 'task:Owner', :writable => true}, - :percent_complete => {:text => 'task:PercentComplete', :writable => true}, - :recurrence => {:text => 'task:Recurrence', :writable => true}, - :start_date => {:text => 'task:StartDate', :writable => true}, - :status => {:text => 'task:Status', :writable => true}, - :status_description => {:text => 'task:StatusDescription', :writable => true}, - :total_work => {:text => 'task:TotalWork', :writable => true}, - :assistant_name => {:text => 'contacts:AssistantName', :writable => true}, - :birthday => {:text => 'contacts:Birthday', :writable => true}, - :business_home_page => {:text => 'contacts:BusinessHomePage', :writable => true}, - :children => {:text => 'contacts:Children', :writable => true}, - :companies => {:text => 'contacts:Companies', :writable => true}, - :company_name => {:text => 'contacts:CompanyName', :writable => true}, - :complete_name => {:text => 'contacts:CompleteName', :writable => true}, - :contact_source => {:text => 'contacts:ContactSource', :writable => true}, - :culture => {:text => 'contacts:Culture', :writable => true}, - :department => {:text => 'contacts:Department', :writable => true}, - :display_name => {:text => 'contacts:DisplayName', :writable => true}, - :email_addresses => {:ftype => :indexed_field_uRI, :text => 'contacts:EmailAddress', :writable => true}, - :file_as => {:text => 'contacts:FileAs', :writable => true}, - :file_as_mapping => {:text => 'contacts:FileAsMapping', :writable => true}, - :generation => {:text => 'contacts:Generation', :writable => true}, - :given_name => {:text => 'contacts:GivenName', :writable => true}, - :has_picture => {:text => 'contacts:HasPicture', :writable => true}, - :im_addresses => {:text => 'contacts:ImAddresses', :writable => true}, - :initials => {:text => 'contacts:Initials', :writable => true}, - :job_title => {:text => 'contacts:JobTitle', :writable => true}, - :manager => {:text => 'contacts:Manager', :writable => true}, - :middle_name => {:text => 'contacts:MiddleName', :writable => true}, - :mileage => {:text => 'contacts:Mileage', :writable => true}, - :nickname => {:text => 'contacts:Nickname', :writable => true}, - :office_location => {:text => 'contacts:OfficeLocation', :writable => true}, - :phone_numbers => {:ftype => :indexed_field_uRI, :text => 'contacts:PhoneNumber', :writable => true}, - :physical_addresses => {:text => 'contacts:PhysicalAddresses', :writable => true}, - :postal_address_index => {:text => 'contacts:PostalAddressIndex', :writable => true}, - :profession => {:text => 'contacts:Profession', :writable => true}, - :spouse_name => {:text => 'contacts:SpouseName', :writable => true}, - :surname => {:text => 'contacts:Surname', :writable => true}, - :wedding_anniversary => {:text => 'contacts:WeddingAnniversary', :writable => true}, - :members => {:text => 'distributionlist:Members', :writable => true}, - :posted_time => {:text => 'postitem:PostedTime', :writable => true}, - :conversation_id => {:text => 'conversation:ConversationId', :writable => true}, - :conversation_topic => {:text => 'conversation:ConversationTopic', :writable => true}, - :unique_recipients => {:text => 'conversation:UniqueRecipients', :writable => true}, - :global_unique_recipients => {:text => 'conversation:GlobalUniqueRecipients', :writable => true}, - :unique_unread_senders => {:text => 'conversation:UniqueUnreadSenders', :writable => true}, - :global_unique_unread_senders => {:text => 'conversation:GlobalUniqueUnreadSenders', :writable => true}, - :unique_senders => {:text => 'conversation:UniqueSenders', :writable => true}, - :global_unique_senders => {:text => 'conversation:GlobalUniqueSenders', :writable => true}, - :last_delivery_time => {:text => 'conversation:LastDeliveryTime', :writable => true}, - :global_last_delivery_time => {:text => 'conversation:GlobalLastDeliveryTime', :writable => true}, - :categories => {:text => 'conversation:Categories', :writable => true}, - :global_categories => {:text => 'conversation:GlobalCategories', :writable => true}, - :flag_status => {:text => 'conversation:FlagStatus', :writable => true}, - :global_flag_status => {:text => 'conversation:GlobalFlagStatus', :writable => true}, - :has_attachments => {:text => 'conversation:HasAttachments', :writable => true}, - :global_has_attachments => {:text => 'conversation:GlobalHasAttachments', :writable => true}, - :message_count => {:text => 'conversation:MessageCount', :writable => true}, - :global_message_count => {:text => 'conversation:GlobalMessageCount', :writable => true}, - :unread_count => {:text => 'conversation:UnreadCount', :writable => true}, - :global_unread_count => {:text => 'conversation:GlobalUnreadCount', :writable => true}, - :size => {:text => 'conversation:Size', :writable => true}, - :global_size => {:text => 'conversation:GlobalSize', :writable => true}, - :item_classes => {:text => 'conversation:ItemClasses', :writable => true}, - :global_item_classes => {:text => 'conversation:GlobalItemClasses', :writable => true}, - :importance => {:text => 'conversation:Importance', :writable => true}, - :global_importance => {:text => 'conversation:GlobalImportance', :writable => true}, - :item_ids => {:text => 'conversation:ItemIds', :writable => true}, - :global_item_ids => {:text => 'conversation:GlobalItemIds', :writable => true} + FIELD_URIS = { + folder_id: { text: 'folder:FolderId', writable: true }, + total_count: { text: 'folder:TotalCount', writable: true }, + child_folder_count: { text: 'folder:ChildFolderCount', writable: true }, + folder_class: { text: 'folder:FolderClass', writable: true }, + search_parameters: { text: 'folder:SearchParameters', writable: true }, + managed_folder_information: { text: 'folder:ManagedFolderInformation', writable: true }, + permission_set: { text: 'folder:PermissionSet', writable: true }, + sharing_effective_rights: { text: 'folder:SharingEffectiveRights', writable: true }, + item_id: { text: 'item:ItemId', writable: true }, + parent_folder_id: { text: 'item:ParentFolderId', writable: true }, + item_class: { text: 'item:ItemClass', writable: true }, + mime_content: { text: 'item:MimeContent', writable: true }, + attachments: { text: 'item:Attachments', writable: true }, + subject: { text: 'item:Subject', writable: true }, + date_time_received: { text: 'item:DateTimeReceived', writable: true }, + in_reply_to: { text: 'item:InReplyTo', writable: true }, + internet_message_headers: { text: 'item:InternetMessageHeaders', writable: true }, + is_associated: { text: 'item:IsAssociated', writable: true }, + is_draft: { text: 'item:IsDraft', writable: true }, + is_from_me: { text: 'item:IsFromMe', writable: true }, + is_resend: { text: 'item:IsResend', writable: true }, + is_submitted: { text: 'item:IsSubmitted', writable: true }, + is_unmodified: { text: 'item:IsUnmodified', writable: true }, + date_time_sent: { text: 'item:DateTimeSent', writable: true }, + date_time_created: { text: 'item:DateTimeCreated', writable: true }, + body: { text: 'item:Body', writable: true }, + response_objects: { text: 'item:ResponseObjects', writable: true }, + sensitivity: { text: 'item:Sensitivity', writable: true }, + reminder_due_by: { text: 'item:ReminderDueBy', writable: true }, + reminder_is_set: { text: 'item:ReminderIsSet', writable: true }, + reminder_minutes_before_start: { text: 'item:ReminderMinutesBeforeStart', writable: true }, + display_to: { text: 'item:DisplayTo', writable: true }, + display_cc: { text: 'item:DisplayCc', writable: true }, + effective_rights: { text: 'item:EffectiveRights', writable: true }, + last_modified_name: { text: 'item:LastModifiedName', writable: true }, + last_modified_time: { text: 'item:LastModifiedTime', writable: true }, + unique_body: { text: 'item:UniqueBody', writable: true }, + web_client_read_form_query_string: { text: 'item:WebClientReadFormQueryString', writable: true }, + web_client_edit_form_query_string: { text: 'item:WebClientEditFormQueryString', writable: true }, + conversation_index: { text: 'message:ConversationIndex', writable: true }, + internet_message_id: { text: 'message:InternetMessageId', writable: true }, + is_read: { text: 'message:IsRead', writable: true }, + is_read_receipt_requested: { text: 'message:IsReadReceiptRequested', writable: true }, + is_delivery_receipt_requested: { text: 'message:IsDeliveryReceiptRequested', writable: true }, + references: { text: 'message:References', writable: true }, + reply_to: { text: 'message:ReplyTo', writable: true }, + from: { text: 'message:From', writable: true }, + sender: { text: 'message:Sender', writable: true }, + to_recipients: { text: 'message:ToRecipients', writable: true }, + cc_recipients: { text: 'message:CcRecipients', writable: true }, + bcc_recipients: { text: 'message:BccRecipients', writable: true }, + associated_calendar_item_id: { text: 'meeting:AssociatedCalendarItemId', writable: true }, + is_delegated: { text: 'meeting:IsDelegated', writable: true }, + is_out_of_date: { text: 'meeting:IsOutOfDate', writable: true }, + has_been_processed: { text: 'meeting:HasBeenProcessed', writable: true }, + response_type: { text: 'meeting:ResponseType', writable: true }, + meeting_request_type: { text: 'meetingRequest:MeetingRequestType', writable: true }, + intended_free_busy_status: { text: 'meetingRequest:IntendedFreeBusyStatus', writable: true }, + start: { text: 'calendar:Start', writable: true }, + end: { text: 'calendar:End', writable: true }, + original_start: { text: 'calendar:OriginalStart', writable: true }, + is_all_day_event: { text: 'calendar:IsAllDayEvent', writable: true }, + legacy_free_busy_status: { text: 'calendar:LegacyFreeBusyStatus', writable: true }, + location: { text: 'calendar:Location', writable: true }, + when: { text: 'calendar:When', writable: true }, + is_meeting: { text: 'calendar:IsMeeting', writable: true }, + is_cancelled: { text: 'calendar:IsCancelled', writable: true }, + meeting_request_was_sent: { text: 'calendar:MeetingRequestWasSent', writable: true }, + is_response_requested: { text: 'calendar:IsResponseRequested', writable: true }, + calendar_item_type: { text: 'calendar:CalendarItemType', writable: true }, + my_response_type: { text: 'calendar:MyResponseType', writable: true }, + organizer: { text: 'calendar:Organizer', writable: true }, + required_attendees: { text: 'calendar:RequiredAttendees', writable: true }, + optional_attendees: { text: 'calendar:OptionalAttendees', writable: true }, + resources: { text: 'calendar:Resources', writable: true }, + conflicting_meeting_count: { text: 'calendar:ConflictingMeetingCount', writable: true }, + adjacent_meeting_count: { text: 'calendar:AdjacentMeetingCount', writable: true }, + conflicting_meetings: { text: 'calendar:ConflictingMeetings', writable: true }, + adjacent_meetings: { text: 'calendar:AdjacentMeetings', writable: true }, + duration: { text: 'calendar:Duration', writable: true }, + time_zone: { text: 'calendar:TimeZone', writable: true }, + appointment_reply_time: { text: 'calendar:AppointmentReplyTime', writable: true }, + appointment_sequence_number: { text: 'calendar:AppointmentSequenceNumber', writable: true }, + appointment_state: { text: 'calendar:AppointmentState', writable: true }, + first_occurrence: { text: 'calendar:FirstOccurrence', writable: true }, + last_occurrence: { text: 'calendar:LastOccurrence', writable: true }, + modified_occurrences: { text: 'calendar:ModifiedOccurrences', writable: true }, + deleted_occurrences: { text: 'calendar:DeletedOccurrences', writable: true }, + meeting_time_zone: { text: 'calendar:MeetingTimeZone', writable: true }, + conference_type: { text: 'calendar:ConferenceType', writable: true }, + allow_new_time_proposal: { text: 'calendar:AllowNewTimeProposal', writable: true }, + is_online_meeting: { text: 'calendar:IsOnlineMeeting', writable: true }, + meeting_workspace_url: { text: 'calendar:MeetingWorkspaceUrl', writable: true }, + net_show_url: { text: 'calendar:NetShowUrl', writable: true }, + u_i_d: { text: 'calendar:UID', writable: true }, + recurrence_id: { text: 'calendar:RecurrenceId', writable: true }, + date_time_stamp: { text: 'calendar:DateTimeStamp', writable: true }, + start_time_zone: { text: 'calendar:StartTimeZone', writable: true }, + end_time_zone: { text: 'calendar:EndTimeZone', writable: true }, + actual_work: { text: 'task:ActualWork', writable: true }, + assigned_time: { text: 'task:AssignedTime', writable: true }, + billing_information: { text: 'task:BillingInformation', writable: true }, + change_count: { text: 'task:ChangeCount', writable: true }, + complete_date: { text: 'task:CompleteDate', writable: true }, + contacts: { text: 'task:Contacts', writable: true }, + delegation_state: { text: 'task:DelegationState', writable: true }, + delegator: { text: 'task:Delegator', writable: true }, + due_date: { text: 'task:DueDate', writable: true }, + is_assignment_editable: { text: 'task:IsAssignmentEditable', writable: true }, + is_complete: { text: 'task:IsComplete', writable: true }, + is_recurring: { text: 'task:IsRecurring', writable: true }, + is_team_task: { text: 'task:IsTeamTask', writable: true }, + owner: { text: 'task:Owner', writable: true }, + percent_complete: { text: 'task:PercentComplete', writable: true }, + recurrence: { text: 'task:Recurrence', writable: true }, + start_date: { text: 'task:StartDate', writable: true }, + status: { text: 'task:Status', writable: true }, + status_description: { text: 'task:StatusDescription', writable: true }, + total_work: { text: 'task:TotalWork', writable: true }, + assistant_name: { text: 'contacts:AssistantName', writable: true }, + birthday: { text: 'contacts:Birthday', writable: true }, + business_home_page: { text: 'contacts:BusinessHomePage', writable: true }, + children: { text: 'contacts:Children', writable: true }, + companies: { text: 'contacts:Companies', writable: true }, + company_name: { text: 'contacts:CompanyName', writable: true }, + complete_name: { text: 'contacts:CompleteName', writable: true }, + contact_source: { text: 'contacts:ContactSource', writable: true }, + culture: { text: 'contacts:Culture', writable: true }, + department: { text: 'contacts:Department', writable: true }, + display_name: { text: 'contacts:DisplayName', writable: true }, + email_addresses: { ftype: :indexed_field_uRI, text: 'contacts:EmailAddress', +writable: true }, + file_as: { text: 'contacts:FileAs', writable: true }, + file_as_mapping: { text: 'contacts:FileAsMapping', writable: true }, + generation: { text: 'contacts:Generation', writable: true }, + given_name: { text: 'contacts:GivenName', writable: true }, + has_picture: { text: 'contacts:HasPicture', writable: true }, + im_addresses: { text: 'contacts:ImAddresses', writable: true }, + initials: { text: 'contacts:Initials', writable: true }, + job_title: { text: 'contacts:JobTitle', writable: true }, + manager: { text: 'contacts:Manager', writable: true }, + middle_name: { text: 'contacts:MiddleName', writable: true }, + mileage: { text: 'contacts:Mileage', writable: true }, + nickname: { text: 'contacts:Nickname', writable: true }, + office_location: { text: 'contacts:OfficeLocation', writable: true }, + phone_numbers: { ftype: :indexed_field_uRI, text: 'contacts:PhoneNumber', +writable: true }, + physical_addresses: { text: 'contacts:PhysicalAddresses', writable: true }, + postal_address_index: { text: 'contacts:PostalAddressIndex', writable: true }, + profession: { text: 'contacts:Profession', writable: true }, + spouse_name: { text: 'contacts:SpouseName', writable: true }, + surname: { text: 'contacts:Surname', writable: true }, + wedding_anniversary: { text: 'contacts:WeddingAnniversary', writable: true }, + members: { text: 'distributionlist:Members', writable: true }, + posted_time: { text: 'postitem:PostedTime', writable: true }, + conversation_id: { text: 'conversation:ConversationId', writable: true }, + conversation_topic: { text: 'conversation:ConversationTopic', writable: true }, + unique_recipients: { text: 'conversation:UniqueRecipients', writable: true }, + global_unique_recipients: { text: 'conversation:GlobalUniqueRecipients', writable: true }, + unique_unread_senders: { text: 'conversation:UniqueUnreadSenders', writable: true }, + global_unique_unread_senders: { text: 'conversation:GlobalUniqueUnreadSenders', writable: true }, + unique_senders: { text: 'conversation:UniqueSenders', writable: true }, + global_unique_senders: { text: 'conversation:GlobalUniqueSenders', writable: true }, + last_delivery_time: { text: 'conversation:LastDeliveryTime', writable: true }, + global_last_delivery_time: { text: 'conversation:GlobalLastDeliveryTime', writable: true }, + categories: { text: 'conversation:Categories', writable: true }, + global_categories: { text: 'conversation:GlobalCategories', writable: true }, + flag_status: { text: 'conversation:FlagStatus', writable: true }, + global_flag_status: { text: 'conversation:GlobalFlagStatus', writable: true }, + has_attachments: { text: 'conversation:HasAttachments', writable: true }, + global_has_attachments: { text: 'conversation:GlobalHasAttachments', writable: true }, + message_count: { text: 'conversation:MessageCount', writable: true }, + global_message_count: { text: 'conversation:GlobalMessageCount', writable: true }, + unread_count: { text: 'conversation:UnreadCount', writable: true }, + global_unread_count: { text: 'conversation:GlobalUnreadCount', writable: true }, + size: { text: 'conversation:Size', writable: true }, + global_size: { text: 'conversation:GlobalSize', writable: true }, + item_classes: { text: 'conversation:ItemClasses', writable: true }, + global_item_classes: { text: 'conversation:GlobalItemClasses', writable: true }, + importance: { text: 'conversation:Importance', writable: true }, + global_importance: { text: 'conversation:GlobalImportance', writable: true }, + item_ids: { text: 'conversation:ItemIds', writable: true }, + global_item_ids: { text: 'conversation:GlobalItemIds', writable: true } } end end diff --git a/lib/ews/types/mailbox_user.rb b/lib/ews/types/mailbox_user.rb index 8db0d6bf..e1b86af3 100644 --- a/lib/ews/types/mailbox_user.rb +++ b/lib/ews/types/mailbox_user.rb @@ -1,23 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - # This represents a Mailbox object in the Exchange data store # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs # @todo Design a Class method that resolves to an Array of MailboxUsers @@ -27,11 +24,11 @@ class MailboxUser MAILBOX_KEY_PATHS = { name: [:name], - email_address: [:email_address], + email_address: [:email_address] } MAILBOX_KEY_TYPES = {} MAILBOX_KEY_ALIAS = { - email: :email_address, + email: :email_address } def initialize(ews, mbox_user) @@ -41,11 +38,11 @@ def initialize(ews, mbox_user) end def out_of_office_settings - mailbox = {:address => self.email_address} + mailbox = { address: email_address } resp = @ews.get_user_oof_settings(mailbox) ewsi = resp.response.clone ewsi.delete(:response_message) - return OutOfOffice.new(self,ewsi) + return OutOfOffice.new(self, ewsi) s = resp[:oof_settings] @oof_state = s[:oof_state][:text] @oof_ext_audience = s[:external_audience][:text] @@ -63,17 +60,17 @@ def out_of_office_settings # @see http://msdn.microsoft.com/en-us/library/aa563800(v=exchg.140) def get_user_availability(email_address, start_time, end_time) opts = { - mailbox_data: [ :email =>{:address => email_address} ], + mailbox_data: [{ email: { address: email_address } }], free_busy_view_options: { - time_window: {start_time: start_time, end_time: end_time}, - } + time_window: { start_time: start_time, end_time: end_time } + } } - resp = (Viewpoint::EWS::EWS.instance).ews.get_user_availability(opts) - if(resp.status == 'Success') - return resp.items - else + resp = Viewpoint::EWS::EWS.instance.ews.get_user_availability(opts) + unless resp.status == 'Success' raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" end + + resp.items end # Adds one or more delegates to a principal's mailbox and sets specific access permissions @@ -93,35 +90,35 @@ def add_delegate!(delegate_email, permissions) # Thanks to Markus Roberts for pointing this out. formatted_perms = {} # Modify permissions so we can pass it to the builders - permissions.each_pair do |k,v| - formatted_perms[k] = {:text => v} + permissions.each_pair do |k, v| + formatted_perms[k] = { text: v } end - resp = (Viewpoint::EWS::EWS.instance).ews.add_delegate(self.email_address, delegate_email, formatted_perms) - if(resp.status == 'Success') - return true - else + resp = Viewpoint::EWS::EWS.instance.ews.add_delegate(email_address, delegate_email, formatted_perms) + unless resp.status == 'Success' raise EwsError, "Could not add delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" end + + true end def update_delegate!(delegate_email, permissions) # Modify permissions so we can pass it to the builders formatted_perms = {} - permissions.each_pair do |k,v| - formatted_perms[k] = {:text => v} + permissions.each_pair do |k, v| + formatted_perms[k] = { text: v } end - resp = (Viewpoint::EWS::EWS.instance).ews.update_delegate(self.email_address, delegate_email, formatted_perms) - if(resp.status == 'Success') - return true - else + resp = Viewpoint::EWS::EWS.instance.ews.update_delegate(email_address, delegate_email, formatted_perms) + unless resp.status == 'Success' raise EwsError, "Could not update delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" end + + true end - def get_delegate_info() - resp = (Viewpoint::EWS::EWS.instance).ews.get_delegate(self.email_address) + def get_delegate_info + Viewpoint::EWS::EWS.instance.ews.get_delegate(email_address) # if(resp.status == 'Success') # return true # else @@ -129,14 +126,11 @@ def get_delegate_info() # end end - private - def simplify! - @ews_item = @ews_item.inject({}){|m,o| - m[o.keys.first] = o.values.first[:text]; - m + @ews_item = @ews_item.each_with_object({}) { |o, m| + m[o.keys.first] = o.values.first[:text] } end @@ -151,6 +145,5 @@ def key_types def key_alias @key_alias ||= super.merge(MAILBOX_KEY_ALIAS) end - end # MailboxUser end # Viewpoint::EWS::Types diff --git a/lib/ews/types/modified_event.rb b/lib/ews/types/modified_event.rb index 123761c7..6287d319 100644 --- a/lib/ews/types/modified_event.rb +++ b/lib/ews/types/modified_event.rb @@ -1,37 +1,29 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class ModifiedEvent < Event + MODIFIED_EVENT_KEY_PATHS = {} - MODIFIED_EVENT_KEY_PATHS = { - } - - MODIFIED_EVENT_KEY_TYPES = { - } - - MODIFIED_EVENT_KEY_ALIAS = { } + MODIFIED_EVENT_KEY_TYPES = {} + MODIFIED_EVENT_KEY_ALIAS = {} private - def key_paths @key_paths ||= super.merge MODIFIED_EVENT_KEY_PATHS end @@ -43,6 +35,5 @@ def key_types def key_alias @key_alias ||= super.merge MODIFIED_EVENT_KEY_ALIAS end - end end diff --git a/lib/ews/types/moved_event.rb b/lib/ews/types/moved_event.rb index b2e334bc..dc1a259c 100644 --- a/lib/ews/types/moved_event.rb +++ b/lib/ews/types/moved_event.rb @@ -1,40 +1,33 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class MovedEvent < Event - MOVED_EVENT_KEY_PATHS = { - :old_item_id => [:old_item_id, :attribs], - :old_folder_id => [:old_folder_id, :attribs], - :old_parent_folder_id => [:old_parent_folder_id, :attribs], - } - - MOVED_EVENT_KEY_TYPES = { + old_item_id: %i[old_item_id attribs], + old_folder_id: %i[old_folder_id attribs], + old_parent_folder_id: %i[old_parent_folder_id attribs] } - MOVED_EVENT_KEY_ALIAS = { } + MOVED_EVENT_KEY_TYPES = {} + MOVED_EVENT_KEY_ALIAS = {} private - def key_paths @key_paths ||= super.merge MOVED_EVENT_KEY_PATHS end @@ -46,6 +39,5 @@ def key_types def key_alias @key_alias ||= super.merge MOVED_EVENT_KEY_ALIAS end - end end diff --git a/lib/ews/types/new_mail_event.rb b/lib/ews/types/new_mail_event.rb index 21ce9899..08f51896 100644 --- a/lib/ews/types/new_mail_event.rb +++ b/lib/ews/types/new_mail_event.rb @@ -1,24 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class NewMailEvent < Event - end end diff --git a/lib/ews/types/out_of_office.rb b/lib/ews/types/out_of_office.rb index e6b7b087..021eccd4 100644 --- a/lib/ews/types/out_of_office.rb +++ b/lib/ews/types/out_of_office.rb @@ -1,36 +1,33 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types + OOF_KEY_PATHS = { + enabled?: %i[oof_settings oof_state], + scheduled?: %i[oof_settings oof_state], + duration: %i[oof_settings duration] + } - OOF_KEY_PATHS = { - :enabled? => [:oof_settings, :oof_state], - :scheduled? => [:oof_settings, :oof_state], - :duration => [:oof_settings, :duration], - } + OOF_KEY_TYPES = { + enabled?: ->(str) { str == :enabled }, + scheduled?: ->(str) { str == :scheduled }, + duration: ->(hsh) { hsh[:start_time]..hsh[:end_time] } + } - OOF_KEY_TYPES = { - :enabled? => ->(str){str == :enabled}, - :scheduled? => ->(str){str == :scheduled}, - :duration => ->(hsh){ hsh[:start_time]..hsh[:end_time] }, - } - - OOF_KEY_ALIAS = {} + OOF_KEY_ALIAS = {} # This represents OutOfOffice settings # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx @@ -56,24 +53,25 @@ def changed? def save! return true unless changed? - opts = { mailbox: {address: user.email_address} }.merge(@ews_item[:oof_settings]) + + opts = { mailbox: { address: user.email_address } }.merge(@ews_item[:oof_settings]) resp = @ews.set_user_oof_settings(opts) - if resp.success? - @changed = false - true - else - raise SaveFailed, "Could not save #{self.class}. #{resp.code}: #{resp.message}" - end + raise SaveFailed, "Could not save #{self.class}. #{resp.code}: #{resp.message}" unless resp.success? + + @changed = false + true end def enable return true if enabled? + @changed = true @ews_item[:oof_settings][:oof_state] = :enabled end def disable return true unless enabled? || scheduled? + @changed = true @ews_item[:oof_settings][:oof_state] = :disabled end @@ -110,8 +108,7 @@ def external_reply=(message) @ews_item[:oof_settings][:external_reply] = message end - -private + private def key_paths @key_paths ||= super.merge(OOF_KEY_PATHS) @@ -133,15 +130,13 @@ def simplify! dur = oof_settings[:duration][:elems].inject(:merge) oof_settings[:duration] = { start_time: DateTime.iso8601(dur[:start_time][:text]), - end_time: DateTime.iso8601(dur[:end_time][:text]) + end_time: DateTime.iso8601(dur[:end_time][:text]) } end - oof_settings[:internal_reply] = oof_settings[:internal_reply][:elems][0][:message][:text] || "" - oof_settings[:external_reply] = oof_settings[:external_reply][:elems][0][:message][:text] || "" + oof_settings[:internal_reply] = oof_settings[:internal_reply][:elems][0][:message][:text] || '' + oof_settings[:external_reply] = oof_settings[:external_reply][:elems][0][:message][:text] || '' @ews_item[:oof_settings] = oof_settings @ews_item[:allow_external_oof] = @ews_item[:allow_external_oof][:text] end - - end #OutOfOffice - + end # OutOfOffice end diff --git a/lib/ews/types/search_folder.rb b/lib/ews/types/search_folder.rb index d180cd9e..3bb2b40e 100644 --- a/lib/ews/types/search_folder.rb +++ b/lib/ews/types/search_folder.rb @@ -3,6 +3,5 @@ class SearchFolder include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::GenericFolder - end end diff --git a/lib/ews/types/status_event.rb b/lib/ews/types/status_event.rb index 51a609e6..b7b12acf 100644 --- a/lib/ews/types/status_event.rb +++ b/lib/ews/types/status_event.rb @@ -1,39 +1,33 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint::EWS::Types - class StatusEvent include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::Item STATUS_EVENT_KEY_PATHS = { - :watermark => [:watermark, :text], + watermark: %i[watermark text] } - private - def key_paths @key_paths ||= STATUS_EVENT_KEY_PATHS end - end end diff --git a/lib/ews/types/task.rb b/lib/ews/types/task.rb index 65f7f9f0..1b718d68 100644 --- a/lib/ews/types/task.rb +++ b/lib/ews/types/task.rb @@ -3,23 +3,23 @@ class Task include Viewpoint::EWS include Viewpoint::EWS::Types include Viewpoint::EWS::Types::Item - + TASK_KEY_PATHS = { - complete?: [:is_complete, :text], - recurring?: [:is_recurring, :text], - start_date: [:start_date, :text], - due_date: [:end_date, :text], - reminder_due_by: [:reminder_due_by, :text], - reminder?: [:reminder_is_set, :text], - percent_complete: [:percent_complete, :text], - status: [:status, :text], - } + complete?: %i[is_complete text], + recurring?: %i[is_recurring text], + start_date: %i[start_date text], + due_date: %i[end_date text], + reminder_due_by: %i[reminder_due_by text], + reminder?: %i[reminder_is_set text], + percent_complete: %i[percent_complete text], + status: %i[status text] + } TASK_KEY_TYPES = { - recurring?: ->(str){str.downcase == 'true'}, - complete?: ->(str){str.downcase == 'true'}, - reminder?: ->(str){str.downcase == 'true'}, - percent_complete: ->(str){str.to_i}, + recurring?: ->(str) { str.downcase == 'true' }, + complete?: ->(str) { str.downcase == 'true' }, + reminder?: ->(str) { str.downcase == 'true' }, + percent_complete: ->(str) { str.to_i } } TASK_KEY_ALIAS = {} @@ -36,6 +36,5 @@ def key_types def key_alias super.merge(TASK_KEY_ALIAS) end - end end diff --git a/lib/ews/types/tasks_folder.rb b/lib/ews/types/tasks_folder.rb index ecbe1148..bbffece1 100644 --- a/lib/ews/types/tasks_folder.rb +++ b/lib/ews/types/tasks_folder.rb @@ -15,16 +15,15 @@ class TasksFolder # @see Template::Task def create_item(attributes) template = Viewpoint::EWS::Template::Task.new attributes - template.saved_item_folder_id = {id: self.id, change_key: self.change_key} + template.saved_item_folder_id = { id: id, change_key: change_key } rm = ews.create_item(template.to_ews_create).response_messages.first if rm && rm.success? Task.new ews, rm.items.first[:task][:elems].first else - if rm - raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" - else - raise EwsCreateItemError, "Could not create item in folder." - end + raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm + + raise EwsCreateItemError, 'Could not create item in folder.' + end end end diff --git a/lib/viewpoint.rb b/lib/viewpoint.rb index dfce8991..19deb8f1 100644 --- a/lib/viewpoint.rb +++ b/lib/viewpoint.rb @@ -1,22 +1,20 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end - -require 'kconv' if(RUBY_VERSION.start_with? '1.9') # bug in rubyntlm with ruby 1.9.x +require 'kconv' if RUBY_VERSION.start_with? '1.9' # bug in rubyntlm with ruby 1.9.x require 'date' require 'base64' require 'nokogiri' diff --git a/lib/viewpoint/logging.rb b/lib/viewpoint/logging.rb index 79d59185..d2dad575 100644 --- a/lib/viewpoint/logging.rb +++ b/lib/viewpoint/logging.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint module EWS diff --git a/lib/viewpoint/logging/config.rb b/lib/viewpoint/logging/config.rb index 5a7c2d08..90b75d7f 100644 --- a/lib/viewpoint/logging/config.rb +++ b/lib/viewpoint/logging/config.rb @@ -1,20 +1,18 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint module EWS diff --git a/lib/viewpoint/string_utils.rb b/lib/viewpoint/string_utils.rb index 1d27b599..574deb4e 100644 --- a/lib/viewpoint/string_utils.rb +++ b/lib/viewpoint/string_utils.rb @@ -1,28 +1,24 @@ -=begin - This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. - - Copyright © 2011 Dan Wanek - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -=end +# This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. +# +# Copyright © 2011 Dan Wanek +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. module Viewpoint - class StringFormatException < ::Exception; end # Collection of utility methods for working with Strings module StringUtils - DURATION_RE = / (?P) ((?\d+)W)? @@ -62,15 +58,16 @@ def camel_case(input) # nil if there is no known duration def iso8601_duration_to_seconds(input) return nil if input.nil? || input.empty? + match_data = DURATION_RE.match(input) - raise(StringFormatException, "Invalid duration given") if match_data.nil? + raise(StringFormatException, 'Invalid duration given') if match_data.nil? + duration = 0 - duration += match_data[:weeks].to_i * 604800 - duration += match_data[:days].to_i * 86400 + duration += match_data[:weeks].to_i * 604_800 + duration += match_data[:days].to_i * 86_400 duration += match_data[:hours].to_i * 3600 duration += match_data[:minutes].to_i * 60 - duration += match_data[:seconds].to_i + duration + match_data[:seconds].to_i end - end # StringUtils end # Viewpoint diff --git a/spec/ews/ews_client_spec.rb b/spec/ews/ews_client_spec.rb index 871d86c6..ea7d005c 100644 --- a/spec/ews/ews_client_spec.rb +++ b/spec/ews/ews_client_spec.rb @@ -1,25 +1,22 @@ -require "spec_helper" +require 'spec_helper' describe Viewpoint::EWSClient do + describe '#set_auto_deepen' do + let(:client) { described_class.new 'http://www.example.com', 'test', 'test' } - describe "#set_auto_deepen" do - let(:client) { described_class.new "http://www.example.com", "test", "test" } - - it "sets autodeepen to true on the web service" do - ews = double "ews" - expect(ews).to receive(:auto_deepen=).with(true) {true} - expect(client).to receive(:ews) {ews} + it 'sets autodeepen to true on the web service' do + ews = double 'ews' + expect(ews).to receive(:auto_deepen=).with(true) { true } + expect(client).to receive(:ews) { ews } client.set_auto_deepen true end it "sets autodeepen to false on the web service with a behavior of 'raise'" do - ews = double "ews" - expect(ews).to receive(:no_auto_deepen_behavior=).with(:raise) {:raise} - expect(ews).to receive(:auto_deepen=).with(false) {false} - expect(client).to receive(:ews).twice {ews} + ews = double 'ews' + expect(ews).to receive(:no_auto_deepen_behavior=).with(:raise) { :raise } + expect(ews).to receive(:auto_deepen=).with(false) { false } + expect(client).to(receive(:ews).twice { ews }) client.set_auto_deepen false end - end - end diff --git a/spec/ews/types/calendar_item_spec.rb b/spec/ews/types/calendar_item_spec.rb index 5a572b48..95bd308c 100644 --- a/spec/ews/types/calendar_item_spec.rb +++ b/spec/ews/types/calendar_item_spec.rb @@ -1,14 +1,12 @@ require 'spec_helper' describe Viewpoint::EWS::Types::CalendarItem do - - describe "#duration" do - it "returns the duration in seconds" do + describe '#duration' do + it 'returns the duration in seconds' do allow_any_instance_of(described_class).to receive(:simplify!) calitem = described_class.new(nil, nil) - allow(calitem).to receive(:duration).and_return("PT0H30M0S") + allow(calitem).to receive(:duration).and_return('PT0H30M0S') expect(calitem.duration_in_seconds).to eql(1800) end end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b9c20545..e3f92044 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,7 +20,7 @@ def specdir end def load_soap(name, type) - File.read("#{specdir}/soap_data/#{name}_#{type}.xml").gsub(%r{>\s+}, '>') + File.read("#{specdir}/soap_data/#{name}_#{type}.xml").gsub(/>\s+/, '>') end end diff --git a/spec/unit/dodgy_file_spec.rb b/spec/unit/dodgy_file_spec.rb index 5ffac1d4..fff3b498 100644 --- a/spec/unit/dodgy_file_spec.rb +++ b/spec/unit/dodgy_file_spec.rb @@ -1,6 +1,6 @@ require_relative '../spec_helper' -describe "Tolerant parsing" do +describe 'Tolerant parsing' do it 'parses a successful response' do soap_resp = load_soap 'dodgy_ews', :response resp = Viewpoint::EWS::SOAP::EwsParser.new(soap_resp).parse(response_class: Viewpoint::EWS::SOAP::EwsResponse) diff --git a/spec/unit/ews_folder_operations_spec.rb b/spec/unit/ews_folder_operations_spec.rb index be58a5dd..32b9b91e 100644 --- a/spec/unit/ews_folder_operations_spec.rb +++ b/spec/unit/ews_folder_operations_spec.rb @@ -1,118 +1,116 @@ require_relative '../spec_helper' -describe "Operations on Exchange Data Services" do +describe 'Operations on Exchange Data Services' do before do con = double('Connection') @ews = Viewpoint::EWS::SOAP::ExchangeWebService.new con, - {:server_version => Viewpoint::EWS::SOAP::VERSION_2010_SP2} + { server_version: Viewpoint::EWS::SOAP::VERSION_2010_SP2 } end - it "generates CreateFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("create_folder", :request))) + it 'generates CreateFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('create_folder', :request))) - fname = "Test Folder" - opts = {:parent_folder_id => {:id => :msgfolderroot}, - :folders => [ :folder => {:display_name => fname} ] } + fname = 'Test Folder' + opts = { parent_folder_id: { id: :msgfolderroot }, + folders: [{ folder: { display_name: fname } }] } @ews.create_folder opts end - it "generates CopyFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("copy_folder", :request))) + it 'generates CopyFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('copy_folder', :request))) - tofid = {:id => 'dest_folder_id'} - @ews.copy_folder tofid, [:id => 'src_folder_id'] + tofid = { id: 'dest_folder_id' } + @ews.copy_folder tofid, [{ id: 'src_folder_id' }] end - it "generates DeleteFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("delete_folder", :request))) + it 'generates DeleteFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('delete_folder', :request))) - fid = "test_folder_id" - opts = {:folder_ids => [id: fid]} + fid = 'test_folder_id' + opts = { folder_ids: [{ id: fid }] } opts[:delete_type] = 'HardDelete' @ews.delete_folder opts end - it "generates FindFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("find_folder", :request))) - - fname = "Test Folder" - opts = {:restriction => - {:is_equal_to => [ - {:field_uRI => {:field_uRI=>'folder:DisplayName'}}, - {:field_uRI_or_constant => {:constant => {:value=>fname}}} - ]} - } - opts[:parent_folder_ids] = [{id: :msgfolderroot}] + it 'generates FindFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('find_folder', :request))) + + fname = 'Test Folder' + opts = { restriction: { is_equal_to: [ + { field_uRI: { field_uRI: 'folder:DisplayName' } }, + { field_uRI_or_constant: { constant: { value: fname } } } + ] } } + opts[:parent_folder_ids] = [{ id: :msgfolderroot }] opts[:traversal] = 'Deep' - opts[:folder_shape] = {:base_shape => 'Default'} + opts[:folder_shape] = { base_shape: 'Default' } @ews.find_folder opts end - context "failing FindFolder XML" do - it "fails with missing key" do - opts = {:parent_folder_ids => [{id: :msgfolderroot}]} - opts[:folder_shape] = {:base_shape => 'Default'} + context 'failing FindFolder XML' do + it 'fails with missing key' do + opts = { parent_folder_ids: [{ id: :msgfolderroot }] } + opts[:folder_shape] = { base_shape: 'Default' } expect { @ews.find_folder(opts) }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) end end - it "generates GetFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("get_folder", :request))) + it 'generates GetFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('get_folder', :request))) - opts = { :folder_ids => [{:id => :msgfolderroot}], - :folder_shape => {:base_shape => 'Default'} } + opts = { folder_ids: [{ id: :msgfolderroot }], + folder_shape: { base_shape: 'Default' } } @ews.get_folder opts end - context "failing GetFolder XML" do - it "fails with missing key" do - opts = { :folder_ids => [{:id => :msgfolderroot}]} + context 'failing GetFolder XML' do + it 'fails with missing key' do + opts = { folder_ids: [{ id: :msgfolderroot }] } expect { @ews.get_folder(opts) }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) end - it "fails with missing subkey" do - opts = { :folder_ids => [{:id => :msgfolderroot}], - :folder_shape => {:blah => 'Default'} } + it 'fails with missing subkey' do + opts = { folder_ids: [{ id: :msgfolderroot }], + folder_shape: { blah: 'Default' } } expect { @ews.get_folder(opts) }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) end end - it "generates MoveFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("move_folder", :request))) + it 'generates MoveFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('move_folder', :request))) - tofid = {:id => 'dest_folder_id'} - @ews.move_folder tofid, [:id => 'src_folder_id'] + tofid = { id: 'dest_folder_id' } + @ews.move_folder tofid, [{ id: 'src_folder_id' }] end - it "generates EmptyFolder XML" do - expect(@ews).to receive(:do_soap_request). - with(match_xml(load_soap("empty_folder", :request))) + it 'generates EmptyFolder XML' do + expect(@ews).to receive(:do_soap_request) + .with(match_xml(load_soap('empty_folder', :request))) - fid = "test_folder_id" - opts = {:folder_ids => [id: fid]} + fid = 'test_folder_id' + opts = { folder_ids: [{ id: fid }] } opts[:delete_type] = Viewpoint::EWS::SOAP::MOVE_TO_DELETED_ITEMS opts[:delete_sub_folders] = false @ews.empty_folder opts end - context "failing EmptyFolder XML" do - it "fails with EwsServerVersionError" do + context 'failing EmptyFolder XML' do + it 'fails with EwsServerVersionError' do @ews.server_version = Viewpoint::EWS::SOAP::VERSION_2010 - fid = "test_folder_id" - opts = {:folder_ids => [id: fid]} + fid = 'test_folder_id' + opts = { folder_ids: [{ id: fid }] } opts[:delete_type] = Viewpoint::EWS::SOAP::MOVE_TO_DELETED_ITEMS opts[:delete_sub_folders] = false expect { @@ -120,14 +118,13 @@ }.to raise_error(Viewpoint::EWS::EwsServerVersionError) end - it "fails with missing key" do - fid = "test_folder_id" - opts = {:folder_ids => [id: fid]} + it 'fails with missing key' do + fid = 'test_folder_id' + opts = { folder_ids: [{ id: fid }] } opts[:delete_type] = Viewpoint::EWS::SOAP::MOVE_TO_DELETED_ITEMS expect { @ews.empty_folder(opts) }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) end end - end diff --git a/spec/unit/ews_parser_spec.rb b/spec/unit/ews_parser_spec.rb index 5f95916a..e3d0b1b4 100644 --- a/spec/unit/ews_parser_spec.rb +++ b/spec/unit/ews_parser_spec.rb @@ -1,12 +1,21 @@ require_relative '../spec_helper' -describe "Exchange Response Parser Functionality" do - +describe 'Exchange Response Parser Functionality' do let(:success_body) { - [{:find_folder_response=>{:elems=>[{:response_messages=>{:elems=>[{:find_folder_response_message=>{:attribs=>{:response_class=>"Success"}, :elems=>{:response_code=>{:text=>"NoError"}, :root_folder=>{:attribs=>{:total_items_in_view=>"1", :includes_last_item_in_range=>"true"}, :elems=>[{:folders=>{:elems=>[{:folder=>{:elems=>[{:folder_id=>{:attribs=>{:id=>"AQAnAH", :change_key=>"AQAAABY"}}}, {:display_name=>{:text=>"TestFolder"}}, {:total_count=>{:text=>"0"}}, {:child_folder_count=>{:text=>"0"}}, {:unread_count=>{:text=>"0"}}]}}]}}]}}}}]}}]}}] + [{ find_folder_response: { elems: [{ response_messages: { elems: [{ find_folder_response_message: { + attribs: { response_class: 'Success' }, elems: { response_code: { text: 'NoError' }, + root_folder: { attribs: { total_items_in_view: '1', includes_last_item_in_range: 'true' }, + elems: [{ folders: { elems: [{ folder: { elems: [ + { folder_id: { attribs: { id: 'AQAnAH', + change_key: 'AQAAABY' } } }, { display_name: { text: 'TestFolder' } }, { total_count: { text: '0' } }, { child_folder_count: { text: '0' } }, { unread_count: { text: '0' } } + ] } }] } }] } } + } }] } }] } }] } let(:error_body) { - [{:find_folder_response=>{:elems=>[{:response_messages=>{:elems=>[{:find_folder_response_message=>{:attribs=>{:response_class=>"Error"}, :elems=>{:message_text=>{:text=>"Id is malformed."}, :response_code=>{:text=>"ErrorInvalidIdMalformed"}, :descriptive_link_key=>{:text=>"0"}}}}]}}]}}] + [{ find_folder_response: { elems: [{ response_messages: { elems: [{ find_folder_response_message: { + attribs: { response_class: 'Error' }, elems: { message_text: { text: 'Id is malformed.' }, +response_code: { text: 'ErrorInvalidIdMalformed' }, descriptive_link_key: { text: '0' } } + } }] } }] } }] } it 'parses a successful response' do @@ -20,5 +29,4 @@ resp = Viewpoint::EWS::SOAP::EwsParser.new(soap_resp).parse expect(resp.body).to eq error_body end - end diff --git a/spec/unit/ews_rooms_operations_spec.rb b/spec/unit/ews_rooms_operations_spec.rb index 410d78dd..f5fdde6f 100644 --- a/spec/unit/ews_rooms_operations_spec.rb +++ b/spec/unit/ews_rooms_operations_spec.rb @@ -1,29 +1,27 @@ require_relative '../spec_helper' -describe "Room operations on Exchange Data Services" do - - #let(:ecli) { Viewpoint::EWSClient.new('dontcare', 'dontcare', 'dontcare') } +describe 'Room operations on Exchange Data Services' do + # let(:ecli) { Viewpoint::EWSClient.new('dontcare', 'dontcare', 'dontcare') } before do con = double('Connection') @ews = Viewpoint::EWS::SOAP::ExchangeWebService.new con, - {:server_version => Viewpoint::EWS::SOAP::VERSION_2010_SP2} + { server_version: Viewpoint::EWS::SOAP::VERSION_2010_SP2 } allow(@ews).to receive(:do_soap_request) end - it "generates GetRooms XML" do + it 'generates GetRooms XML' do expect(@ews).to receive(:do_soap_request) do |request_document| - doc = request_document.to_s.gsub(%r{>\s+}, '>') - expect(doc).to eq load_soap("get_rooms", :request) + doc = request_document.to_s.gsub(/>\s+/, '>') + expect(doc).to eq load_soap('get_rooms', :request) end @ews.get_rooms 'TestRoomList@test.microsoft.com' end - it "generates GetRoomLists XML" do + it 'generates GetRoomLists XML' do expect(@ews).to receive(:do_soap_request) do |request_document| - doc = request_document.to_s.gsub(%r{>\s+}, '>') - expect(doc).to eq load_soap("get_room_lists", :request) + doc = request_document.to_s.gsub(/>\s+/, '>') + expect(doc).to eq load_soap('get_room_lists', :request) end.and_return(double(:resp)) @ews.get_room_lists end - end diff --git a/spec/unit/ews_soap_free_busy_response_spec.rb b/spec/unit/ews_soap_free_busy_response_spec.rb index a6317403..0d8c24a8 100644 --- a/spec/unit/ews_soap_free_busy_response_spec.rb +++ b/spec/unit/ews_soap_free_busy_response_spec.rb @@ -1,152 +1,150 @@ require_relative '../spec_helper' describe Viewpoint::EWS::SOAP::EwsSoapFreeBusyResponse do - let(:ews) { Viewpoint::EWS::SOAP::ExchangeWebService.new(double(:connection)) } - ERROR_INVALID_SMTP_ADDRESS = <\s+}, '>') - - - - - - - - - - - E-mail address <>SMTP:foobar is not a valid SMTP address. - ErrorInvalidSmtpAddress - 0 - - Microsoft.Exchange.InfoWorker.Common.Availability.InvalidSmtpAddressException - 5035 - ANY-SERVER-NAME - - - - None - - - - - - -EOS + ERROR_INVALID_SMTP_ADDRESS = <<~EOS.gsub(/>\s+/, '>') + + + + + + + + + + + E-mail address <>SMTP:foobar is not a valid SMTP address. + ErrorInvalidSmtpAddress + 0 + + Microsoft.Exchange.InfoWorker.Common.Availability.InvalidSmtpAddressException + 5035 + ANY-SERVER-NAME + + + + None + + + + + + + EOS - context "Exchange responds with InvalidSmtpAddress error" do + context 'Exchange responds with InvalidSmtpAddress error' do let(:ews) { Viewpoint::EWS::SOAP::ExchangeWebService.new(double(:connection)) } - let(:resp) { ews.parse_soap_response(ERROR_INVALID_SMTP_ADDRESS, :response_class => described_class) } + let(:resp) { ews.parse_soap_response(ERROR_INVALID_SMTP_ADDRESS, response_class: described_class) } - it "should deliver the error code" do - expect(resp.code).to eq "ErrorInvalidSmtpAddress" + it 'should deliver the error code' do + expect(resp.code).to eq 'ErrorInvalidSmtpAddress' end - it "should extract the response message" do + it 'should extract the response message' do extracted_response_message = { - attribs: {response_class: "Error"}, + attribs: { response_class: 'Error' }, elems: [ - {message_text: {text: "E-mail address <>SMTP:foobar is not a valid SMTP address."}}, - {response_code: {text: "ErrorInvalidSmtpAddress"}}, - {descriptive_link_key: {text: "0"}}, - {message_xml: { + { message_text: { text: 'E-mail address <>SMTP:foobar is not a valid SMTP address.' } }, + { response_code: { text: 'ErrorInvalidSmtpAddress' } }, + { descriptive_link_key: { text: '0' } }, + { message_xml: { elems: [ - {exception_type: {text: "Microsoft.Exchange.InfoWorker.Common.Availability.InvalidSmtpAddressException"}}, - {exception_code: {text: "5035"}}, - {exception_server_name: {text: "ANY-SERVER-NAME"}} + { exception_type: { text: 'Microsoft.Exchange.InfoWorker.Common.Availability.InvalidSmtpAddressException' } }, + { exception_code: { text: '5035' } }, + { exception_server_name: { text: 'ANY-SERVER-NAME' } } ] - }} + } } ] } expect(resp.response_message).to eq extracted_response_message end end - CALENDAR_EVENT_ARRAY = <\s+}, '>') - - - - - - - - - - - NoError - - - Detailed - - - 2013-05-15T12:00:00 - 2013-05-15T13:00:00 - Busy - - dontcare - any subject - any location - true - false - false - false - false - - - - - - - - - -EOS + CALENDAR_EVENT_ARRAY = <<~EOS.gsub(/>\s+/, '>') + + + + + + + + + + + NoError + + + Detailed + + + 2013-05-15T12:00:00 + 2013-05-15T13:00:00 + Busy + + dontcare + any subject + any location + true + false + false + false + false + + + + + + + + + + EOS - context "FreeBusyView with content" do - let(:resp) { ews.parse_soap_response(CALENDAR_EVENT_ARRAY, :response_class => described_class) } + context 'FreeBusyView with content' do + let(:resp) { ews.parse_soap_response(CALENDAR_EVENT_ARRAY, response_class: described_class) } - it "response should be successful" do - expect(resp.status).to eq "Success" + it 'response should be successful' do + expect(resp.status).to eq 'Success' end - it "the calendar_event_array should have one element" do + it 'the calendar_event_array should have one element' do expect(resp.calendar_event_array.length).to eq 1 end end - EMPTY_RESPONSE = <\s+}, '>') - - - - - - - - - - - NoError - - - Detailed - - - - - - -EOS + EMPTY_RESPONSE = <<~EOS.gsub(/>\s+/, '>') + + + + + + + + + + + NoError + + + Detailed + + + + + + + EOS - context "empty FreeBusyView" do - let(:resp) { ews.parse_soap_response(EMPTY_RESPONSE, :response_class => described_class) } + context 'empty FreeBusyView' do + let(:resp) { ews.parse_soap_response(EMPTY_RESPONSE, response_class: described_class) } - it "response should be success" do - expect(resp.status).to eq "Success" + it 'response should be success' do + expect(resp.status).to eq 'Success' end - it "the calendar_event_array should be an empty list" do + it 'the calendar_event_array should be an empty list' do expect(resp.calendar_event_array).to eq [] end end - end diff --git a/spec/unit/folder_accessors_spec.rb b/spec/unit/folder_accessors_spec.rb index dc5ec0c8..da92d47e 100644 --- a/spec/unit/folder_accessors_spec.rb +++ b/spec/unit/folder_accessors_spec.rb @@ -2,31 +2,31 @@ module ResponseObjects def self.folders - [ {:folder => {:display_name => {:text => 'Inbox'}}}, - {:folder => {:display_name => {:text => 'Drafts'}}}, - {:tasks_folder => {:display_name => {:text => 'Tasks'}}} ] + [{ folder: { display_name: { text: 'Inbox' } } }, + { folder: { display_name: { text: 'Drafts' } } }, + { tasks_folder: { display_name: { text: 'Tasks' } } }] end end describe Viewpoint::EWS::FolderAccessors do before do - ews = double("ews") - @ecli = double("EWSClient") + ews = double('ews') + @ecli = double('EWSClient') @ecli.extend subject allow(@ecli).to receive(:ews).and_return ews allow(@ecli).to receive(:merge_restrictions!) end - context "ensure FolderAccessors methods are returning good data" do - context "methods utilizing ExchangeWebService#find_folder" do + context 'ensure FolderAccessors methods are returning good data' do + context 'methods utilizing ExchangeWebService#find_folder' do before do resp = OpenStruct.new resp.status = 'Success' - rhash = {:elems => {:root_folder => {:elems => [{:folders =>{:elems => ResponseObjects.folders}}]}}} + rhash = { elems: { root_folder: { elems: [{ folders: { elems: ResponseObjects.folders } }] } } } resp.response_message = rhash allow(@ecli.ews).to receive(:find_folder).with(an_instance_of(Hash)).and_return resp - cbn = double("ClassByName") - allow(cbn).to receive(:new).and_return double("FolderMock") + cbn = double('ClassByName') + allow(cbn).to receive(:new).and_return double('FolderMock') allow(@ecli).to receive(:class_by_name).and_return cbn end @@ -34,15 +34,15 @@ def self.folders expect(@ecli.folders).to be_instance_of(Array) end end - context "methods utilizing ExchangeWebService#get_folder" do + context 'methods utilizing ExchangeWebService#get_folder' do before do resp = OpenStruct.new resp.status = 'Success' - rhash = {:elems => {:folders =>{:elems => ResponseObjects.folders}}} + rhash = { elems: { folders: { elems: ResponseObjects.folders } } } resp.response_message = rhash allow(@ecli.ews).to receive(:get_folder).with(an_instance_of(Hash)).and_return resp - cbn = double("ClassByName") - allow(cbn).to receive(:new).and_return double("Folder") + cbn = double('ClassByName') + allow(cbn).to receive(:new).and_return double('Folder') allow(@ecli).to receive(:class_by_name).and_return cbn end it '#get_folder should return a Folder' do @@ -51,7 +51,7 @@ def self.folders end end - context "ensure that exceptions are being raised" do + context 'ensure that exceptions are being raised' do before do resp = OpenStruct.new resp.status = 'Failure' @@ -69,5 +69,4 @@ def self.folders }.to raise_error(Viewpoint::EWS::EwsError) end end - end diff --git a/spec/unit/item_accessors_spec.rb b/spec/unit/item_accessors_spec.rb index e18e9225..adf890ec 100644 --- a/spec/unit/item_accessors_spec.rb +++ b/spec/unit/item_accessors_spec.rb @@ -2,21 +2,21 @@ module ResponseObjects def self.folders - [ {:folder => {:display_name => {:text => 'Inbox'}}}, - {:folder => {:display_name => {:text => 'Drafts'}}}, - {:tasks_folder => {:display_name => {:text => 'Tasks'}}} ] + [{ folder: { display_name: { text: 'Inbox' } } }, + { folder: { display_name: { text: 'Drafts' } } }, + { tasks_folder: { display_name: { text: 'Tasks' } } }] end end describe Viewpoint::EWS::ItemAccessors do before do - ews = double("ews") - @ecli = double("EWSClient") + ews = double('ews') + @ecli = double('EWSClient') @ecli.extend subject allow(@ecli).to receive(:ews).and_return(ews) end - context "ensure that exceptions are being raised" do + context 'ensure that exceptions are being raised' do before do resp = OpenStruct.new rm = OpenStruct.new @@ -26,12 +26,12 @@ def self.folders end it '#get_item should raise an exception' do expect { - @ecli.get_item("MyItemId") + @ecli.get_item('MyItemId') }.to raise_error(Viewpoint::EWS::EwsItemNotFound) end end - context "get_item_args should handle :occurrence_item_id" do + context 'get_item_args should handle :occurrence_item_id' do class GetItemArgsAccessor include Viewpoint::EWS::ItemAccessors def call_get_item_args(*args) @@ -39,33 +39,34 @@ def call_get_item_args(*args) end end - it "should handle an :occurrence_item_id hash" do - occurrence_item_id = {:occurrence_item_id => {:recurring_master_id => 'rid1', :change_key => 'ck', :instance_index => 1}} + it 'should handle an :occurrence_item_id hash' do + occurrence_item_id = { occurrence_item_id: { recurring_master_id: 'rid1', change_key: 'ck', +instance_index: 1 } } result = GetItemArgsAccessor.new.call_get_item_args(occurrence_item_id, {}) expect(result[:item_ids]).to eq [occurrence_item_id] end - it "should handle an Array of :occurrence_item_id hashes" do - occurrences = [ - {:occurrence_item_id => {:recurring_master_id => 'rid1', :change_key => 'ck1', :instance_index => 1}}, - {:occurrence_item_id => {:recurring_master_id => 'rid2', :change_key => 'ck2', :instance_index => 2}}, - {:occurrence_item_id => {:recurring_master_id => 'rid3', :change_key => 'ck3', :instance_index => 3}}, + it 'should handle an Array of :occurrence_item_id hashes' do + occurrences = [ + { occurrence_item_id: { recurring_master_id: 'rid1', change_key: 'ck1', instance_index: 1 } }, + { occurrence_item_id: { recurring_master_id: 'rid2', change_key: 'ck2', instance_index: 2 } }, + { occurrence_item_id: { recurring_master_id: 'rid3', change_key: 'ck3', instance_index: 3 } } ] result = GetItemArgsAccessor.new.call_get_item_args(occurrences, {}) expect(result[:item_ids]).to eq occurrences end - it "should handle an :id hash" do - id = {:id => 'id1', :change_key => 'ck1'} + it 'should handle an :id hash' do + id = { id: 'id1', change_key: 'ck1' } result = GetItemArgsAccessor.new.call_get_item_args(id, {}) - expect(result[:item_ids]).to eq [{:item_id => {:id => 'id1', :change_key => 'ck1'}}] + expect(result[:item_ids]).to eq [{ item_id: { id: 'id1', change_key: 'ck1' } }] end - it "should handle an Array of id strings" do - ids = ['id1', 'id2', 'id3'] + it 'should handle an Array of id strings' do + ids = %w[id1 id2 id3] result = GetItemArgsAccessor.new.call_get_item_args(ids, {}) - expect(result[:item_ids]).to eq [{:item_id=>{:id => 'id1'}},{:item_id=>{:id => 'id2'}},{:item_id=>{:id => 'id3'}}] + expect(result[:item_ids]).to eq [{ item_id: { id: 'id1' } }, { item_id: { id: 'id2' } }, + { item_id: { id: 'id3' } }] end end - end diff --git a/spec/unit/mailbox_accessors_spec.rb b/spec/unit/mailbox_accessors_spec.rb index 5afacfe4..b664456a 100644 --- a/spec/unit/mailbox_accessors_spec.rb +++ b/spec/unit/mailbox_accessors_spec.rb @@ -4,7 +4,7 @@ let(:ecli) { Viewpoint::EWSClient.new('dontcare', 'dontcare', 'dontcare') } let(:recipients) { ['anyrecipient'] } let(:timezone_request) do -" + " 0 0 @@ -25,32 +25,29 @@ let(:default_parameters) do { - :start_time => (Time.now - 1).iso8601, - :end_time => Time.now.iso8601, - :requested_view => :detailed + start_time: (Time.now - 1).iso8601, + end_time: Time.now.iso8601, + requested_view: :detailed } end - context "#get_user_availability" do - - it "should care about timezones" do + context '#get_user_availability' do + it 'should care about timezones' do expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| - expect(request_document.at_xpath('//soap:Envelope/soap:Body//t:TimeZone').to_s).to eq timezone_request - end. - and_return(double(:resp, :status => 'Success')) + expect(request_document.at_xpath('//soap:Envelope/soap:Body//t:TimeZone').to_s).to eq timezone_request + end + .and_return(double(:resp, status: 'Success')) ecli.get_user_availability( recipients, default_parameters.merge( - :time_zone => { - :bias => 0, - :standard_time => {:bias => 0}, - :daylight_time => {:bias => 0} + time_zone: { + bias: 0, + standard_time: { bias: 0 }, + daylight_time: { bias: 0 } } ) ) end - end - end diff --git a/spec/unit/meeting_accessors_spec.rb b/spec/unit/meeting_accessors_spec.rb index d2dd46e6..3ca61089 100644 --- a/spec/unit/meeting_accessors_spec.rb +++ b/spec/unit/meeting_accessors_spec.rb @@ -8,11 +8,11 @@ id: 'foo-id', change_key: 'change-key', text: 'example text', - sensitivity: 'Private', + sensitivity: 'Private' } end - context "#accept_meeting" do + context '#accept_meeting' do let(:create_item_request) do " @@ -27,17 +27,17 @@ " end - it "should form valid accept item request" do + it 'should form valid accept item request' do expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end. - and_return(double(:resp, :status => 'Success')) + end + .and_return(double(:resp, status: 'Success')) ecli.accept_meeting(default_opts) end end - context "#decline_meeting" do + context '#decline_meeting' do let(:create_item_request) do " @@ -52,17 +52,17 @@ " end - it "should form valid accept item request" do + it 'should form valid accept item request' do expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end. - and_return(double(:resp, :status => 'success')) + end + .and_return(double(:resp, status: 'success')) ecli.decline_meeting(default_opts) end end - context "#tentatively_accept_meeting" do + context '#tentatively_accept_meeting' do let(:create_item_request) do " @@ -77,11 +77,11 @@ " end - it "should form valid accept item request" do + it 'should form valid accept item request' do expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end. - and_return(double(:resp, :status => 'success')) + end + .and_return(double(:resp, status: 'success')) ecli.tentatively_accept_meeting(default_opts) end diff --git a/spec/unit/soap/builders/ews_builder_spec.rb b/spec/unit/soap/builders/ews_builder_spec.rb index 1c6cd6c7..2ef68334 100644 --- a/spec/unit/soap/builders/ews_builder_spec.rb +++ b/spec/unit/soap/builders/ews_builder_spec.rb @@ -5,18 +5,18 @@ let(:namespaces) { Viewpoint::EWS::SOAP::NAMESPACES } it 'should #build a basic structure' do - doc = builder.build!(server_version: Viewpoint::EWS::SOAP::VERSION_2007) {|s| } + doc = builder.build!(server_version: Viewpoint::EWS::SOAP::VERSION_2007) { |s| } expect(doc).to match_xml(load_soap('basic', :request)) end it 'should build BodyType' do - doc = builder.build! do |section| + doc = builder.build! { |section| if section == :body builder.body_type!(:html) builder.body_type!(:text) builder.body_type!(:best) end - end + } expect(doc.xpath('//t:BodyType[1]').text).to eq('HTML') expect(doc.xpath('//t:BodyType[2]').text).to eq('Text') expect(doc.xpath('//t:BodyType[3]').text).to eq('Best') @@ -25,44 +25,43 @@ it 'should format various Time inputs' do expect(builder.send(:format_time, Date.iso8601('2013-01-01'))).to eq('2013-01-01T00:00:00+00:00') expect(builder.send(:format_time, DateTime.iso8601('2013-01-01T23:01:00-05:00'))).to eq('2013-01-02T04:01:00+00:00') - expect {builder.send(:format_time, true)}.to raise_error(Viewpoint::EWS::EwsBadArgumentError) - expect {builder.send(:format_time, 'asdf')}.to raise_error(Viewpoint::EWS::EwsBadArgumentError) + expect { builder.send(:format_time, true) }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) + expect { builder.send(:format_time, 'asdf') }.to raise_error(Viewpoint::EWS::EwsBadArgumentError) end it 'should contain time zone context' do - doc = builder.build!(time_zone_context: {id: 'SpaceTime'}) + doc = builder.build!(time_zone_context: { id: 'SpaceTime' }) selector = "//soap:Header/t:TimeZoneContext/t:TimeZoneDefinition[@Id='SpaceTime']" expect(doc.root.xpath(selector, namespaces)).to be_any end - describe "#field_uRI" do - let(:field_uri_string) { "message:ToRecipients" } + describe '#field_uRI' do + let(:field_uri_string) { 'message:ToRecipients' } let(:match_string) { "" } before do - allow(builder).to receive(:ews_types_builder).and_return builder.nbuild + allow(builder).to receive(:ews_types_builder).and_return builder.nbuild end - it "builds a fieldURI from a String" do + it 'builds a fieldURI from a String' do builder.field_uri(field_uri_string) ndoc = builder.nbuild.doc expect(ndoc.children.length).to eq(1) expect(ndoc.children.first.to_s).to eq(match_string) end - it "builds a fieldURI from a Hash with key :field_uRI" do - builder.field_uri({field_uRI: field_uri_string}) + it 'builds a fieldURI from a Hash with key :field_uRI' do + builder.field_uri({ field_uRI: field_uri_string }) ndoc = builder.nbuild.doc expect(ndoc.children.length).to eq(1) expect(ndoc.children.first.to_s).to eq(match_string) end - it "builds a fieldURI from a Hash with key :field_uri" do - builder.field_uri({field_uri: field_uri_string}) + it 'builds a fieldURI from a Hash with key :field_uri' do + builder.field_uri({ field_uri: field_uri_string }) ndoc = builder.nbuild.doc expect(ndoc.children.length).to eq(1) expect(ndoc.children.first.to_s).to eq(match_string) end - end end diff --git a/spec/viewpoint/string_utils_spec.rb b/spec/viewpoint/string_utils_spec.rb index 45923114..f2305372 100644 --- a/spec/viewpoint/string_utils_spec.rb +++ b/spec/viewpoint/string_utils_spec.rb @@ -2,65 +2,64 @@ describe Viewpoint::StringUtils do before do - self.extend Viewpoint::StringUtils + extend Viewpoint::StringUtils end - describe "#ruby_case" do - it "transforms RubyCase to ruby_case" do - expect(self.send(:ruby_case,"RubyCase")).to eql("ruby_case") + describe '#ruby_case' do + it 'transforms RubyCase to ruby_case' do + expect(send(:ruby_case, 'RubyCase')).to eql('ruby_case') end - it "transforms ruby_case to ruby_case" do - expect(self.send(:ruby_case,"ruby_case")).to eql("ruby_case") + it 'transforms ruby_case to ruby_case' do + expect(send(:ruby_case, 'ruby_case')).to eql('ruby_case') end - it "transforms ThisIsATest to this_is_a_test" do - expect(self.send(:ruby_case,"ThisIsATest")).to eql("this_is_a_test") + it 'transforms ThisIsATest to this_is_a_test' do + expect(send(:ruby_case, 'ThisIsATest')).to eql('this_is_a_test') end end - describe "#camel_case" do - it "transforms camel_case to CamelCase" do - expect(self.send(:camel_case,"camel_case")).to eql("CamelCase") + describe '#camel_case' do + it 'transforms camel_case to CamelCase' do + expect(send(:camel_case, 'camel_case')).to eql('CamelCase') end - it "transforms CamelCase to CamelCase" do - expect(self.send(:camel_case,"CamelCase")).to eql("CamelCase") + it 'transforms CamelCase to CamelCase' do + expect(send(:camel_case, 'CamelCase')).to eql('CamelCase') end - it "transforms this_is_a_test to ThisIsATest" do - expect(self.send(:camel_case,"this_is_a_test")).to eql("ThisIsATest") + it 'transforms this_is_a_test to ThisIsATest' do + expect(send(:camel_case, 'this_is_a_test')).to eql('ThisIsATest') end end - describe "#iso8601_duration_to_seconds" do - it "returns nil if the input is nil" do - expect(self.send(:iso8601_duration_to_seconds,nil)).to be_nil + describe '#iso8601_duration_to_seconds' do + it 'returns nil if the input is nil' do + expect(send(:iso8601_duration_to_seconds, nil)).to be_nil end - it "returns nil if the input is empty" do - expect(self.send(:iso8601_duration_to_seconds,"")).to be_nil + it 'returns nil if the input is empty' do + expect(send(:iso8601_duration_to_seconds, '')).to be_nil end - it "parses P4D" do - expect(self.send(:iso8601_duration_to_seconds,"P4D")).to eql(345600) + it 'parses P4D' do + expect(send(:iso8601_duration_to_seconds, 'P4D')).to eql(345_600) end - it "parses P2DT4H1M23S" do - expect(self.send(:iso8601_duration_to_seconds,"P2DT4H1M23S")).to eql(187283) + it 'parses P2DT4H1M23S' do + expect(send(:iso8601_duration_to_seconds, 'P2DT4H1M23S')).to eql(187_283) end - it "parses P15DT5H0M20S" do - expect(self.send(:iso8601_duration_to_seconds,"P15DT5H0M20S")).to eql(1314020) + it 'parses P15DT5H0M20S' do + expect(send(:iso8601_duration_to_seconds, 'P15DT5H0M20S')).to eql(1_314_020) end - it "parses P2DT4H1M23S" do - expect(self.send(:iso8601_duration_to_seconds,"P2DT4H1M23S")).to eql(187283) + it 'parses P2DT4H1M23S' do + expect(send(:iso8601_duration_to_seconds, 'P2DT4H1M23S')).to eql(187_283) end - it "parses P7W" do - expect(self.send(:iso8601_duration_to_seconds,"P7W")).to eql(4233600) + it 'parses P7W' do + expect(send(:iso8601_duration_to_seconds, 'P7W')).to eql(4_233_600) end end - end diff --git a/viewpoint.gemspec b/viewpoint.gemspec index b08783c8..0ad667b9 100644 --- a/viewpoint.gemspec +++ b/viewpoint.gemspec @@ -1,7 +1,6 @@ -# -*- encoding: utf-8 -*- require 'date' -version = File.read(File.expand_path("../VERSION", __FILE__)).strip +version = File.read(File.expand_path('VERSION', __dir__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY @@ -20,17 +19,18 @@ Gem::Specification.new do |s| s.files = Dir['Changelog.txt', 'README.md', 'TODO', 'lib/**/*'] s.require_path = 'lib' - s.rdoc_options = %w(-x test/ -x examples/) - s.extra_rdoc_files = %w(README.md) + s.rdoc_options = %w[-x test/ -x examples/] + s.extra_rdoc_files = %w[README.md] - s.add_runtime_dependency 'nokogiri', '!=1.12.3', '!=1.12.2', '!=1.12.1', '!=1.12.0' s.add_runtime_dependency 'httpclient' - s.add_runtime_dependency 'rubyntlm' s.add_runtime_dependency 'logging' - s.add_runtime_dependency 'syslog' s.add_runtime_dependency 'mutex_m' + s.add_runtime_dependency 'nokogiri', '!=1.12.3', '!=1.12.2', '!=1.12.1', '!=1.12.0' + s.add_runtime_dependency 'rubyntlm' + s.add_runtime_dependency 'syslog' # ostruct and base64 are bundled (not default) gems on modern Rubies; # declare them so `require` keeps working under `bundle exec`. - s.add_runtime_dependency 'ostruct' s.add_runtime_dependency 'base64' + s.add_runtime_dependency 'ostruct' + s.metadata['rubygems_mfa_required'] = 'true' end From 4927e50bed74c25a409f46812b65c1316f0c954f Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:55:40 +0000 Subject: [PATCH 02/12] Lint: add frozen_string_literal magic comments (fix one mutation hazard) --- Gemfile | 1 + Guardfile | 1 + Rakefile | 1 + lib/ews/calendar_accessors.rb | 1 + lib/ews/connection.rb | 1 + lib/ews/connection_helper.rb | 1 + lib/ews/convert_accessors.rb | 1 + lib/ews/errors.rb | 1 + lib/ews/ews_client.rb | 1 + lib/ews/exceptions/exceptions.rb | 1 + lib/ews/folder_accessors.rb | 1 + lib/ews/impersonation.rb | 1 + lib/ews/item_accessors.rb | 1 + lib/ews/mailbox_accessors.rb | 1 + lib/ews/meeting_accessors.rb | 1 + lib/ews/message_accessors.rb | 1 + lib/ews/push_subscription_accessors.rb | 1 + lib/ews/room_accessors.rb | 1 + lib/ews/roomlist_accessors.rb | 1 + lib/ews/soap.rb | 1 + lib/ews/soap/builders/ews_builder.rb | 1 + lib/ews/soap/ews_response.rb | 1 + lib/ews/soap/ews_soap_availability_response.rb | 1 + lib/ews/soap/ews_soap_free_busy_response.rb | 1 + lib/ews/soap/ews_soap_response.rb | 1 + lib/ews/soap/ews_soap_room_response.rb | 1 + lib/ews/soap/ews_soap_roomlist_response.rb | 1 + lib/ews/soap/exchange_availability.rb | 1 + lib/ews/soap/exchange_data_services.rb | 1 + lib/ews/soap/exchange_notification.rb | 1 + lib/ews/soap/exchange_synchronization.rb | 1 + lib/ews/soap/exchange_time_zones.rb | 1 + lib/ews/soap/exchange_user_configuration.rb | 1 + lib/ews/soap/exchange_web_service.rb | 3 ++- lib/ews/soap/parsers/ews_parser.rb | 1 + lib/ews/soap/parsers/ews_sax_document.rb | 1 + lib/ews/soap/response_message.rb | 1 + lib/ews/soap/responses/create_attachment_response_message.rb | 1 + lib/ews/soap/responses/create_item_response_message.rb | 1 + lib/ews/soap/responses/find_item_response_message.rb | 1 + lib/ews/soap/responses/get_events_response_message.rb | 1 + lib/ews/soap/responses/send_notification_response_message.rb | 1 + lib/ews/soap/responses/subscribe_response_message.rb | 1 + .../soap/responses/sync_folder_hierarchy_response_message.rb | 1 + lib/ews/soap/responses/sync_folder_items_response_message.rb | 1 + lib/ews/templates/calendar_item.rb | 1 + lib/ews/templates/forward_item.rb | 1 + lib/ews/templates/message.rb | 1 + lib/ews/templates/reply_to_item.rb | 1 + lib/ews/templates/task.rb | 1 + lib/ews/types.rb | 1 + lib/ews/types/attachment.rb | 1 + lib/ews/types/attendee.rb | 1 + lib/ews/types/calendar_folder.rb | 1 + lib/ews/types/calendar_item.rb | 1 + lib/ews/types/contact.rb | 1 + lib/ews/types/contacts_folder.rb | 1 + lib/ews/types/copied_event.rb | 1 + lib/ews/types/created_event.rb | 1 + lib/ews/types/deleted_event.rb | 1 + lib/ews/types/distribution_list.rb | 1 + lib/ews/types/event.rb | 1 + lib/ews/types/export_items_response_message.rb | 1 + lib/ews/types/file_attachment.rb | 1 + lib/ews/types/folder.rb | 1 + lib/ews/types/free_busy_changed_event.rb | 1 + lib/ews/types/generic_folder.rb | 1 + lib/ews/types/item.rb | 1 + lib/ews/types/item_attachment.rb | 1 + lib/ews/types/item_field_uri_map.rb | 1 + lib/ews/types/mailbox_user.rb | 1 + lib/ews/types/meeting_cancellation.rb | 1 + lib/ews/types/meeting_message.rb | 1 + lib/ews/types/meeting_request.rb | 1 + lib/ews/types/meeting_response.rb | 1 + lib/ews/types/message.rb | 1 + lib/ews/types/modified_event.rb | 1 + lib/ews/types/moved_event.rb | 1 + lib/ews/types/new_mail_event.rb | 1 + lib/ews/types/out_of_office.rb | 1 + lib/ews/types/post_item.rb | 1 + lib/ews/types/search_folder.rb | 1 + lib/ews/types/status_event.rb | 1 + lib/ews/types/task.rb | 1 + lib/ews/types/tasks_folder.rb | 1 + lib/viewpoint.rb | 1 + lib/viewpoint/logging.rb | 1 + lib/viewpoint/logging/config.rb | 1 + lib/viewpoint/string_utils.rb | 1 + spec/ews/ews_client_spec.rb | 1 + spec/ews/types/calendar_item_spec.rb | 1 + spec/spec_helper.rb | 1 + spec/unit/dodgy_file_spec.rb | 1 + spec/unit/ews_folder_operations_spec.rb | 1 + spec/unit/ews_parser_spec.rb | 1 + spec/unit/ews_rooms_operations_spec.rb | 1 + spec/unit/ews_soap_free_busy_response_spec.rb | 1 + spec/unit/folder_accessors_spec.rb | 1 + spec/unit/item_accessors_spec.rb | 1 + spec/unit/mailbox_accessors_spec.rb | 1 + spec/unit/meeting_accessors_spec.rb | 1 + spec/unit/soap/builders/ews_builder_spec.rb | 1 + spec/viewpoint/string_utils_spec.rb | 1 + spec/xml_matcher.rb | 1 + viewpoint.gemspec | 1 + 105 files changed, 106 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 8821e3c1..bae48233 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ +# frozen_string_literal: true source 'https://rubygems.org/' gemspec diff --git a/Guardfile b/Guardfile index c8c4e12d..11d274a8 100644 --- a/Guardfile +++ b/Guardfile @@ -1,3 +1,4 @@ +# frozen_string_literal: true # A sample Guardfile # More info at https://github.com/guard/guard#readme diff --git a/Rakefile b/Rakefile index 457e86ac..8009d8c5 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'rubygems' require 'bundler' diff --git a/lib/ews/calendar_accessors.rb b/lib/ews/calendar_accessors.rb index e1662baf..b47e8657 100644 --- a/lib/ews/calendar_accessors.rb +++ b/lib/ews/calendar_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Mark McCahill diff --git a/lib/ews/connection.rb b/lib/ews/connection.rb index 65185166..3bf6ac5c 100644 --- a/lib/ews/connection.rb +++ b/lib/ews/connection.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/connection_helper.rb b/lib/ews/connection_helper.rb index a422a5e7..171006dc 100644 --- a/lib/ews/connection_helper.rb +++ b/lib/ews/connection_helper.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/convert_accessors.rb b/lib/ews/convert_accessors.rb index 3adc4e02..cab831ed 100644 --- a/lib/ews/convert_accessors.rb +++ b/lib/ews/convert_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Dan Wanek diff --git a/lib/ews/errors.rb b/lib/ews/errors.rb index 21786245..c39600fe 100644 --- a/lib/ews/errors.rb +++ b/lib/ews/errors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/ews_client.rb b/lib/ews/ews_client.rb index c1070c64..45729a72 100644 --- a/lib/ews/ews_client.rb +++ b/lib/ews/ews_client.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'ews/folder_accessors' require 'ews/item_accessors' require 'ews/message_accessors' diff --git a/lib/ews/exceptions/exceptions.rb b/lib/ews/exceptions/exceptions.rb index 4610278a..508a820d 100644 --- a/lib/ews/exceptions/exceptions.rb +++ b/lib/ews/exceptions/exceptions.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/folder_accessors.rb b/lib/ews/folder_accessors.rb index ee029bc7..b91128d5 100644 --- a/lib/ews/folder_accessors.rb +++ b/lib/ews/folder_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/impersonation.rb b/lib/ews/impersonation.rb index bd5fc5ad..fbca999b 100644 --- a/lib/ews/impersonation.rb +++ b/lib/ews/impersonation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS ConnectingSID = { UPN: 'PrincipalName', diff --git a/lib/ews/item_accessors.rb b/lib/ews/item_accessors.rb index 4ba092a4..0375e298 100644 --- a/lib/ews/item_accessors.rb +++ b/lib/ews/item_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/mailbox_accessors.rb b/lib/ews/mailbox_accessors.rb index 05844a96..1e77e54f 100644 --- a/lib/ews/mailbox_accessors.rb +++ b/lib/ews/mailbox_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/meeting_accessors.rb b/lib/ews/meeting_accessors.rb index 84160f3b..4fc962ba 100644 --- a/lib/ews/meeting_accessors.rb +++ b/lib/ews/meeting_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::MeetingAccessors include Viewpoint::EWS diff --git a/lib/ews/message_accessors.rb b/lib/ews/message_accessors.rb index 02a2ef72..467265c5 100644 --- a/lib/ews/message_accessors.rb +++ b/lib/ews/message_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/push_subscription_accessors.rb b/lib/ews/push_subscription_accessors.rb index 51a6744c..6c768338 100644 --- a/lib/ews/push_subscription_accessors.rb +++ b/lib/ews/push_subscription_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/room_accessors.rb b/lib/ews/room_accessors.rb index f7634f12..ea4a03ec 100644 --- a/lib/ews/room_accessors.rb +++ b/lib/ews/room_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock diff --git a/lib/ews/roomlist_accessors.rb b/lib/ews/roomlist_accessors.rb index a670a1f7..beceb569 100644 --- a/lib/ews/roomlist_accessors.rb +++ b/lib/ews/roomlist_accessors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock diff --git a/lib/ews/soap.rb b/lib/ews/soap.rb index 79db52eb..2ee9fddb 100644 --- a/lib/ews/soap.rb +++ b/lib/ews/soap.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index ff857ad6..8af462fa 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/ews_response.rb b/lib/ews/soap/ews_response.rb index 1de29cb6..792f16ec 100644 --- a/lib/ews/soap/ews_response.rb +++ b/lib/ews/soap/ews_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/ews_soap_availability_response.rb b/lib/ews/soap/ews_soap_availability_response.rb index 3b9a4c82..34807bf8 100644 --- a/lib/ews/soap/ews_soap_availability_response.rb +++ b/lib/ews/soap/ews_soap_availability_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/ews_soap_free_busy_response.rb b/lib/ews/soap/ews_soap_free_busy_response.rb index 7dbeb231..5b61789c 100644 --- a/lib/ews/soap/ews_soap_free_busy_response.rb +++ b/lib/ews/soap/ews_soap_free_busy_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Mark McCahill diff --git a/lib/ews/soap/ews_soap_response.rb b/lib/ews/soap/ews_soap_response.rb index 7932e263..07a10a0a 100644 --- a/lib/ews/soap/ews_soap_response.rb +++ b/lib/ews/soap/ews_soap_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/ews_soap_room_response.rb b/lib/ews/soap/ews_soap_room_response.rb index cab27265..6f927f1d 100644 --- a/lib/ews/soap/ews_soap_room_response.rb +++ b/lib/ews/soap/ews_soap_room_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock diff --git a/lib/ews/soap/ews_soap_roomlist_response.rb b/lib/ews/soap/ews_soap_roomlist_response.rb index e09545fe..54edb2e6 100644 --- a/lib/ews/soap/ews_soap_roomlist_response.rb +++ b/lib/ews/soap/ews_soap_roomlist_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock diff --git a/lib/ews/soap/exchange_availability.rb b/lib/ews/soap/exchange_availability.rb index 124a20fc..b491eadc 100644 --- a/lib/ews/soap/exchange_availability.rb +++ b/lib/ews/soap/exchange_availability.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::SOAP # Exchange Availability operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx diff --git a/lib/ews/soap/exchange_data_services.rb b/lib/ews/soap/exchange_data_services.rb index 7cd5ba90..94bd1a86 100644 --- a/lib/ews/soap/exchange_data_services.rb +++ b/lib/ews/soap/exchange_data_services.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::SOAP # Exchange Data Service operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx diff --git a/lib/ews/soap/exchange_notification.rb b/lib/ews/soap/exchange_notification.rb index 717dfd27..d876f881 100644 --- a/lib/ews/soap/exchange_notification.rb +++ b/lib/ews/soap/exchange_notification.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/exchange_synchronization.rb b/lib/ews/soap/exchange_synchronization.rb index 1ad63544..95ac73b1 100644 --- a/lib/ews/soap/exchange_synchronization.rb +++ b/lib/ews/soap/exchange_synchronization.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/exchange_time_zones.rb b/lib/ews/soap/exchange_time_zones.rb index 15f52414..7d1d1bcf 100644 --- a/lib/ews/soap/exchange_time_zones.rb +++ b/lib/ews/soap/exchange_time_zones.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::SOAP module ExchangeTimeZones include Viewpoint::EWS::SOAP diff --git a/lib/ews/soap/exchange_user_configuration.rb b/lib/ews/soap/exchange_user_configuration.rb index 4551005c..27b74830 100644 --- a/lib/ews/soap/exchange_user_configuration.rb +++ b/lib/ews/soap/exchange_user_configuration.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::SOAP # Exchange User Configuration operations as listed in the EWS Documentation. # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx diff --git a/lib/ews/soap/exchange_web_service.rb b/lib/ews/soap/exchange_web_service.rb index 579909f4..2109c256 100644 --- a/lib/ews/soap/exchange_web_service.rb +++ b/lib/ews/soap/exchange_web_service.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -244,7 +245,7 @@ def validate_param(opts, key, required, default_val = nil) def validate_version(exchange_version) return unless server_version < exchange_version - msg = 'The operation you are attempting to use is not compatible with' + msg = +'The operation you are attempting to use is not compatible with' msg << " your configured Exchange Server version(#{server_version})." msg << " You must be running at least version (#{exchange_version})." raise EwsServerVersionError, msg diff --git a/lib/ews/soap/parsers/ews_parser.rb b/lib/ews/soap/parsers/ews_parser.rb index 72afde56..84cabfa3 100644 --- a/lib/ews/soap/parsers/ews_parser.rb +++ b/lib/ews/soap/parsers/ews_parser.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/parsers/ews_sax_document.rb b/lib/ews/soap/parsers/ews_sax_document.rb index 03d5333b..4f8349d6 100644 --- a/lib/ews/soap/parsers/ews_sax_document.rb +++ b/lib/ews/soap/parsers/ews_sax_document.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/response_message.rb b/lib/ews/soap/response_message.rb index 39346e78..df5a2c42 100644 --- a/lib/ews/soap/response_message.rb +++ b/lib/ews/soap/response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/create_attachment_response_message.rb b/lib/ews/soap/responses/create_attachment_response_message.rb index 0b38b558..d16906ce 100644 --- a/lib/ews/soap/responses/create_attachment_response_message.rb +++ b/lib/ews/soap/responses/create_attachment_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/create_item_response_message.rb b/lib/ews/soap/responses/create_item_response_message.rb index a7ba9b56..abcfd750 100644 --- a/lib/ews/soap/responses/create_item_response_message.rb +++ b/lib/ews/soap/responses/create_item_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/find_item_response_message.rb b/lib/ews/soap/responses/find_item_response_message.rb index 2d581089..c002e610 100644 --- a/lib/ews/soap/responses/find_item_response_message.rb +++ b/lib/ews/soap/responses/find_item_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/get_events_response_message.rb b/lib/ews/soap/responses/get_events_response_message.rb index c7cfbd62..e1f48273 100644 --- a/lib/ews/soap/responses/get_events_response_message.rb +++ b/lib/ews/soap/responses/get_events_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/send_notification_response_message.rb b/lib/ews/soap/responses/send_notification_response_message.rb index 4a471565..61947b01 100644 --- a/lib/ews/soap/responses/send_notification_response_message.rb +++ b/lib/ews/soap/responses/send_notification_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/subscribe_response_message.rb b/lib/ews/soap/responses/subscribe_response_message.rb index f8c181f8..2945b0bc 100644 --- a/lib/ews/soap/responses/subscribe_response_message.rb +++ b/lib/ews/soap/responses/subscribe_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb index 7c298bff..8e631d2d 100644 --- a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/responses/sync_folder_items_response_message.rb b/lib/ews/soap/responses/sync_folder_items_response_message.rb index 550ed2eb..a64f1273 100644 --- a/lib/ews/soap/responses/sync_folder_items_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_items_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/templates/calendar_item.rb b/lib/ews/templates/calendar_item.rb index 221c75fe..ddf09dfa 100644 --- a/lib/ews/templates/calendar_item.rb +++ b/lib/ews/templates/calendar_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Template # Template for creating CalendarItems diff --git a/lib/ews/templates/forward_item.rb b/lib/ews/templates/forward_item.rb index b473920f..edba1379 100644 --- a/lib/ews/templates/forward_item.rb +++ b/lib/ews/templates/forward_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Template class ForwardItem < Message diff --git a/lib/ews/templates/message.rb b/lib/ews/templates/message.rb index add1be6a..135e331e 100644 --- a/lib/ews/templates/message.rb +++ b/lib/ews/templates/message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Template class Message < OpenStruct diff --git a/lib/ews/templates/reply_to_item.rb b/lib/ews/templates/reply_to_item.rb index 7c671fd5..388d5131 100644 --- a/lib/ews/templates/reply_to_item.rb +++ b/lib/ews/templates/reply_to_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Template class ReplyToItem < Message diff --git a/lib/ews/templates/task.rb b/lib/ews/templates/task.rb index ff10abff..a16e5f65 100644 --- a/lib/ews/templates/task.rb +++ b/lib/ews/templates/task.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Template # Template for creating Tasks diff --git a/lib/ews/types.rb b/lib/ews/types.rb index 71197e9b..5d6cbd58 100644 --- a/lib/ews/types.rb +++ b/lib/ews/types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS module Types include Viewpoint::StringUtils diff --git a/lib/ews/types/attachment.rb b/lib/ews/types/attachment.rb index 145e7efd..042f9fc6 100644 --- a/lib/ews/types/attachment.rb +++ b/lib/ews/types/attachment.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/attendee.rb b/lib/ews/types/attendee.rb index 80b7843a..47cade45 100644 --- a/lib/ews/types/attendee.rb +++ b/lib/ews/types/attendee.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/calendar_folder.rb b/lib/ews/types/calendar_folder.rb index 775c381e..e3bede33 100644 --- a/lib/ews/types/calendar_folder.rb +++ b/lib/ews/types/calendar_folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class CalendarFolder include Viewpoint::EWS diff --git a/lib/ews/types/calendar_item.rb b/lib/ews/types/calendar_item.rb index 41aff1d6..47672deb 100644 --- a/lib/ews/types/calendar_item.rb +++ b/lib/ews/types/calendar_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class CalendarItem include Viewpoint::EWS diff --git a/lib/ews/types/contact.rb b/lib/ews/types/contact.rb index c68a82f1..e5a9c0a7 100644 --- a/lib/ews/types/contact.rb +++ b/lib/ews/types/contact.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class Contact include Viewpoint::EWS diff --git a/lib/ews/types/contacts_folder.rb b/lib/ews/types/contacts_folder.rb index 76233d3b..c92aae63 100644 --- a/lib/ews/types/contacts_folder.rb +++ b/lib/ews/types/contacts_folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class ContactsFolder include Viewpoint::EWS diff --git a/lib/ews/types/copied_event.rb b/lib/ews/types/copied_event.rb index a9ce4ac1..51879583 100644 --- a/lib/ews/types/copied_event.rb +++ b/lib/ews/types/copied_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/created_event.rb b/lib/ews/types/created_event.rb index 16501668..6f98efe9 100644 --- a/lib/ews/types/created_event.rb +++ b/lib/ews/types/created_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/deleted_event.rb b/lib/ews/types/deleted_event.rb index e20c5fbc..cf4d8abe 100644 --- a/lib/ews/types/deleted_event.rb +++ b/lib/ews/types/deleted_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/distribution_list.rb b/lib/ews/types/distribution_list.rb index e297c865..35bca9bc 100644 --- a/lib/ews/types/distribution_list.rb +++ b/lib/ews/types/distribution_list.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class DistributionList include Viewpoint::EWS diff --git a/lib/ews/types/event.rb b/lib/ews/types/event.rb index f92040bb..ba171413 100644 --- a/lib/ews/types/event.rb +++ b/lib/ews/types/event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/export_items_response_message.rb b/lib/ews/types/export_items_response_message.rb index 14ec17cf..9b77be76 100644 --- a/lib/ews/types/export_items_response_message.rb +++ b/lib/ews/types/export_items_response_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class ExportItemsResponseMessage include Viewpoint::EWS diff --git a/lib/ews/types/file_attachment.rb b/lib/ews/types/file_attachment.rb index d4d552ae..b9f9d685 100644 --- a/lib/ews/types/file_attachment.rb +++ b/lib/ews/types/file_attachment.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/folder.rb b/lib/ews/types/folder.rb index 3ab267ca..69904ceb 100644 --- a/lib/ews/types/folder.rb +++ b/lib/ews/types/folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class Folder include Viewpoint::EWS diff --git a/lib/ews/types/free_busy_changed_event.rb b/lib/ews/types/free_busy_changed_event.rb index eb3d095a..eb929207 100644 --- a/lib/ews/types/free_busy_changed_event.rb +++ b/lib/ews/types/free_busy_changed_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/generic_folder.rb b/lib/ews/types/generic_folder.rb index 96bf6df0..69b0bf02 100644 --- a/lib/ews/types/generic_folder.rb +++ b/lib/ews/types/generic_folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/item.rb b/lib/ews/types/item.rb index e2e439c2..a5125791 100644 --- a/lib/ews/types/item.rb +++ b/lib/ews/types/item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types module Item include Viewpoint::EWS diff --git a/lib/ews/types/item_attachment.rb b/lib/ews/types/item_attachment.rb index f71a20a1..ac057c07 100644 --- a/lib/ews/types/item_attachment.rb +++ b/lib/ews/types/item_attachment.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/item_field_uri_map.rb b/lib/ews/types/item_field_uri_map.rb index 039855e5..2ec0e888 100644 --- a/lib/ews/types/item_field_uri_map.rb +++ b/lib/ews/types/item_field_uri_map.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/mailbox_user.rb b/lib/ews/types/mailbox_user.rb index e1b86af3..34828920 100644 --- a/lib/ews/types/mailbox_user.rb +++ b/lib/ews/types/mailbox_user.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/meeting_cancellation.rb b/lib/ews/types/meeting_cancellation.rb index 02cfd076..d2cbc7c4 100644 --- a/lib/ews/types/meeting_cancellation.rb +++ b/lib/ews/types/meeting_cancellation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class MeetingCancellation include Viewpoint::EWS diff --git a/lib/ews/types/meeting_message.rb b/lib/ews/types/meeting_message.rb index 6a2d6c5a..c66c78c4 100644 --- a/lib/ews/types/meeting_message.rb +++ b/lib/ews/types/meeting_message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class MeetingMessage include Viewpoint::EWS diff --git a/lib/ews/types/meeting_request.rb b/lib/ews/types/meeting_request.rb index c0064c24..4b7200b1 100644 --- a/lib/ews/types/meeting_request.rb +++ b/lib/ews/types/meeting_request.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class MeetingRequest include Viewpoint::EWS diff --git a/lib/ews/types/meeting_response.rb b/lib/ews/types/meeting_response.rb index baa3e6b8..1df6692a 100644 --- a/lib/ews/types/meeting_response.rb +++ b/lib/ews/types/meeting_response.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class MeetingResponse include Viewpoint::EWS diff --git a/lib/ews/types/message.rb b/lib/ews/types/message.rb index 5c22aef5..26b2f733 100644 --- a/lib/ews/types/message.rb +++ b/lib/ews/types/message.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class Message include Viewpoint::EWS diff --git a/lib/ews/types/modified_event.rb b/lib/ews/types/modified_event.rb index 6287d319..6e2434da 100644 --- a/lib/ews/types/modified_event.rb +++ b/lib/ews/types/modified_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/moved_event.rb b/lib/ews/types/moved_event.rb index dc1a259c..5a178ee7 100644 --- a/lib/ews/types/moved_event.rb +++ b/lib/ews/types/moved_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/new_mail_event.rb b/lib/ews/types/new_mail_event.rb index 08f51896..d62e51d0 100644 --- a/lib/ews/types/new_mail_event.rb +++ b/lib/ews/types/new_mail_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/out_of_office.rb b/lib/ews/types/out_of_office.rb index 021eccd4..167b04a6 100644 --- a/lib/ews/types/out_of_office.rb +++ b/lib/ews/types/out_of_office.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/post_item.rb b/lib/ews/types/post_item.rb index 935f7dde..3f2b63ac 100644 --- a/lib/ews/types/post_item.rb +++ b/lib/ews/types/post_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class PostItem include Viewpoint::EWS diff --git a/lib/ews/types/search_folder.rb b/lib/ews/types/search_folder.rb index 3bb2b40e..5be18b13 100644 --- a/lib/ews/types/search_folder.rb +++ b/lib/ews/types/search_folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class SearchFolder include Viewpoint::EWS diff --git a/lib/ews/types/status_event.rb b/lib/ews/types/status_event.rb index b7b12acf..01086d3e 100644 --- a/lib/ews/types/status_event.rb +++ b/lib/ews/types/status_event.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/task.rb b/lib/ews/types/task.rb index 1b718d68..8d3b861a 100644 --- a/lib/ews/types/task.rb +++ b/lib/ews/types/task.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class Task include Viewpoint::EWS diff --git a/lib/ews/types/tasks_folder.rb b/lib/ews/types/tasks_folder.rb index bbffece1..b63d7ed1 100644 --- a/lib/ews/types/tasks_folder.rb +++ b/lib/ews/types/tasks_folder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Viewpoint::EWS::Types class TasksFolder include Viewpoint::EWS diff --git a/lib/viewpoint.rb b/lib/viewpoint.rb index 19deb8f1..606196c6 100644 --- a/lib/viewpoint.rb +++ b/lib/viewpoint.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/logging.rb b/lib/viewpoint/logging.rb index d2dad575..49ce9882 100644 --- a/lib/viewpoint/logging.rb +++ b/lib/viewpoint/logging.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/logging/config.rb b/lib/viewpoint/logging/config.rb index 90b75d7f..76d9aad9 100644 --- a/lib/viewpoint/logging/config.rb +++ b/lib/viewpoint/logging/config.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/string_utils.rb b/lib/viewpoint/string_utils.rb index 574deb4e..acc6c282 100644 --- a/lib/viewpoint/string_utils.rb +++ b/lib/viewpoint/string_utils.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/spec/ews/ews_client_spec.rb b/spec/ews/ews_client_spec.rb index ea7d005c..f4e87c54 100644 --- a/spec/ews/ews_client_spec.rb +++ b/spec/ews/ews_client_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'spec_helper' describe Viewpoint::EWSClient do diff --git a/spec/ews/types/calendar_item_spec.rb b/spec/ews/types/calendar_item_spec.rb index 95bd308c..38d0cf57 100644 --- a/spec/ews/types/calendar_item_spec.rb +++ b/spec/ews/types/calendar_item_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'spec_helper' describe Viewpoint::EWS::Types::CalendarItem do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e3f92044..fd230f0d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true $: << File.dirname(__FILE__) + '/../lib/' require 'viewpoint' require 'viewpoint/logging/config' diff --git a/spec/unit/dodgy_file_spec.rb b/spec/unit/dodgy_file_spec.rb index fff3b498..56ae5ca8 100644 --- a/spec/unit/dodgy_file_spec.rb +++ b/spec/unit/dodgy_file_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe 'Tolerant parsing' do diff --git a/spec/unit/ews_folder_operations_spec.rb b/spec/unit/ews_folder_operations_spec.rb index 32b9b91e..b5ce0836 100644 --- a/spec/unit/ews_folder_operations_spec.rb +++ b/spec/unit/ews_folder_operations_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe 'Operations on Exchange Data Services' do diff --git a/spec/unit/ews_parser_spec.rb b/spec/unit/ews_parser_spec.rb index e3d0b1b4..8021ca42 100644 --- a/spec/unit/ews_parser_spec.rb +++ b/spec/unit/ews_parser_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe 'Exchange Response Parser Functionality' do diff --git a/spec/unit/ews_rooms_operations_spec.rb b/spec/unit/ews_rooms_operations_spec.rb index f5fdde6f..607ce158 100644 --- a/spec/unit/ews_rooms_operations_spec.rb +++ b/spec/unit/ews_rooms_operations_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe 'Room operations on Exchange Data Services' do diff --git a/spec/unit/ews_soap_free_busy_response_spec.rb b/spec/unit/ews_soap_free_busy_response_spec.rb index 0d8c24a8..cfda704a 100644 --- a/spec/unit/ews_soap_free_busy_response_spec.rb +++ b/spec/unit/ews_soap_free_busy_response_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe Viewpoint::EWS::SOAP::EwsSoapFreeBusyResponse do diff --git a/spec/unit/folder_accessors_spec.rb b/spec/unit/folder_accessors_spec.rb index da92d47e..ddd8b098 100644 --- a/spec/unit/folder_accessors_spec.rb +++ b/spec/unit/folder_accessors_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' module ResponseObjects diff --git a/spec/unit/item_accessors_spec.rb b/spec/unit/item_accessors_spec.rb index adf890ec..afac9514 100644 --- a/spec/unit/item_accessors_spec.rb +++ b/spec/unit/item_accessors_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' module ResponseObjects diff --git a/spec/unit/mailbox_accessors_spec.rb b/spec/unit/mailbox_accessors_spec.rb index b664456a..5d0572af 100644 --- a/spec/unit/mailbox_accessors_spec.rb +++ b/spec/unit/mailbox_accessors_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe Viewpoint::EWS::MailboxAccessors do diff --git a/spec/unit/meeting_accessors_spec.rb b/spec/unit/meeting_accessors_spec.rb index 3ca61089..cf9f5d27 100644 --- a/spec/unit/meeting_accessors_spec.rb +++ b/spec/unit/meeting_accessors_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../spec_helper' describe Viewpoint::EWS::MeetingAccessors do diff --git a/spec/unit/soap/builders/ews_builder_spec.rb b/spec/unit/soap/builders/ews_builder_spec.rb index 2ef68334..6f7650b8 100644 --- a/spec/unit/soap/builders/ews_builder_spec.rb +++ b/spec/unit/soap/builders/ews_builder_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative '../../../spec_helper' describe Viewpoint::EWS::SOAP::EwsBuilder do diff --git a/spec/viewpoint/string_utils_spec.rb b/spec/viewpoint/string_utils_spec.rb index f2305372..f606ea15 100644 --- a/spec/viewpoint/string_utils_spec.rb +++ b/spec/viewpoint/string_utils_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'spec_helper' describe Viewpoint::StringUtils do diff --git a/spec/xml_matcher.rb b/spec/xml_matcher.rb index 276143c8..244637b9 100644 --- a/spec/xml_matcher.rb +++ b/spec/xml_matcher.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true RSpec::Matchers.define :match_xml do |expected| match do |actual| compare_xml(actual, expected) diff --git a/viewpoint.gemspec b/viewpoint.gemspec index 0ad667b9..6648d24e 100644 --- a/viewpoint.gemspec +++ b/viewpoint.gemspec @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'date' version = File.read(File.expand_path('VERSION', __dir__)).strip From 1af479ddaf62a41c0f881239c7d0a0042558f13a Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:55:55 +0000 Subject: [PATCH 03/12] Lint: remove end-of-module comments (Style/CommentedKeyword) --- lib/ews/calendar_accessors.rb | 2 +- lib/ews/convert_accessors.rb | 2 +- lib/ews/exceptions/exceptions.rb | 2 +- lib/ews/item_accessors.rb | 2 +- lib/ews/mailbox_accessors.rb | 2 +- lib/ews/message_accessors.rb | 2 +- lib/ews/push_subscription_accessors.rb | 2 +- lib/ews/room_accessors.rb | 2 +- lib/ews/roomlist_accessors.rb | 2 +- lib/ews/soap.rb | 6 +++--- lib/ews/soap/builders/ews_builder.rb | 4 ++-- lib/ews/soap/ews_response.rb | 4 ++-- lib/ews/soap/ews_soap_availability_response.rb | 4 ++-- lib/ews/soap/ews_soap_free_busy_response.rb | 4 ++-- lib/ews/soap/ews_soap_response.rb | 4 ++-- lib/ews/soap/ews_soap_room_response.rb | 4 ++-- lib/ews/soap/ews_soap_roomlist_response.rb | 4 ++-- lib/ews/soap/exchange_availability.rb | 2 +- lib/ews/soap/exchange_data_services.rb | 2 +- lib/ews/soap/exchange_notification.rb | 2 +- lib/ews/soap/exchange_synchronization.rb | 2 +- lib/ews/soap/exchange_user_configuration.rb | 2 +- lib/ews/soap/exchange_web_service.rb | 4 ++-- lib/ews/soap/parsers/ews_parser.rb | 4 ++-- lib/ews/soap/response_message.rb | 2 +- .../soap/responses/create_attachment_response_message.rb | 4 ++-- lib/ews/soap/responses/create_item_response_message.rb | 4 ++-- lib/ews/soap/responses/find_item_response_message.rb | 4 ++-- lib/ews/soap/responses/get_events_response_message.rb | 4 ++-- .../soap/responses/send_notification_response_message.rb | 4 ++-- lib/ews/soap/responses/subscribe_response_message.rb | 4 ++-- .../responses/sync_folder_hierarchy_response_message.rb | 4 ++-- .../soap/responses/sync_folder_items_response_message.rb | 4 ++-- lib/ews/types/attendee.rb | 4 ++-- lib/ews/types/mailbox_user.rb | 4 ++-- lib/ews/types/out_of_office.rb | 2 +- lib/viewpoint/logging.rb | 2 +- lib/viewpoint/logging/config.rb | 2 +- lib/viewpoint/string_utils.rb | 4 ++-- 39 files changed, 61 insertions(+), 61 deletions(-) diff --git a/lib/ews/calendar_accessors.rb b/lib/ews/calendar_accessors.rb index b47e8657..e016069c 100644 --- a/lib/ews/calendar_accessors.rb +++ b/lib/ews/calendar_accessors.rb @@ -29,4 +29,4 @@ def event_start_time(the_event) def event_end_time(the_event) the_event[:calendar_event][:elems][1][:end_time][:text] end -end # Viewpoint::EWS::CalendarAccessors +end diff --git a/lib/ews/convert_accessors.rb b/lib/ews/convert_accessors.rb index cab831ed..f71a665a 100644 --- a/lib/ews/convert_accessors.rb +++ b/lib/ews/convert_accessors.rb @@ -51,4 +51,4 @@ def convert_id_parser(resp) raise EwsError, "Could not convert id. #{rm.code}: #{rm.message_text}" end end -end # Viewpoint::EWS::ItemAccessors +end diff --git a/lib/ews/exceptions/exceptions.rb b/lib/ews/exceptions/exceptions.rb index 508a820d..d0beed01 100644 --- a/lib/ews/exceptions/exceptions.rb +++ b/lib/ews/exceptions/exceptions.rb @@ -55,4 +55,4 @@ class SaveFailed < EwsError; end class EwsCreateItemError < EwsError; end class EwsSendItemError < EwsError; end -end # Viewpoint::EWS +end diff --git a/lib/ews/item_accessors.rb b/lib/ews/item_accessors.rb index 0375e298..dbf51048 100644 --- a/lib/ews/item_accessors.rb +++ b/lib/ews/item_accessors.rb @@ -235,4 +235,4 @@ def export_items_parser(resp) end items end -end # Viewpoint::EWS::ItemAccessors +end diff --git a/lib/ews/mailbox_accessors.rb b/lib/ews/mailbox_accessors.rb index 1e77e54f..59f6d1b5 100644 --- a/lib/ews/mailbox_accessors.rb +++ b/lib/ews/mailbox_accessors.rb @@ -86,4 +86,4 @@ def get_user_availability_parser(resp) resp end -end # Viewpoint::EWS::MailboxAccessors +end diff --git a/lib/ews/message_accessors.rb b/lib/ews/message_accessors.rb index 467265c5..a187e223 100644 --- a/lib/ews/message_accessors.rb +++ b/lib/ews/message_accessors.rb @@ -86,4 +86,4 @@ def parse_message(msg) mtype = msg.keys.first class_by_name(mtype).new(ews, msg[mtype]) end -end # Viewpoint::EWS::MessageAccessors +end diff --git a/lib/ews/push_subscription_accessors.rb b/lib/ews/push_subscription_accessors.rb index 6c768338..a6bf408f 100644 --- a/lib/ews/push_subscription_accessors.rb +++ b/lib/ews/push_subscription_accessors.rb @@ -26,4 +26,4 @@ def parse_send_notification(msg) rmsg end -end # Viewpoint::EWS::PushSubscriptionAccessors +end diff --git a/lib/ews/room_accessors.rb b/lib/ews/room_accessors.rb index ea4a03ec..cd5adfdf 100644 --- a/lib/ews/room_accessors.rb +++ b/lib/ews/room_accessors.rb @@ -41,4 +41,4 @@ def get_rooms_parser(resp) resp end -end # Viewpoint::EWS::RoomAccessors +end diff --git a/lib/ews/roomlist_accessors.rb b/lib/ews/roomlist_accessors.rb index beceb569..98dc2acf 100644 --- a/lib/ews/roomlist_accessors.rb +++ b/lib/ews/roomlist_accessors.rb @@ -40,4 +40,4 @@ def get_room_lists_parser(resp) resp end -end # Viewpoint::EWS::RoomlistAccessors +end diff --git a/lib/ews/soap.rb b/lib/ews/soap.rb index 2ee9fddb..4236ffa9 100644 --- a/lib/ews/soap.rb +++ b/lib/ews/soap.rb @@ -56,6 +56,6 @@ def initialize @log = Logging.logger[self.class.name.to_s.to_sym] @default_ns = NAMESPACES["xmlns:#{NS_EWS_MESSAGES}"] end - end # SOAP - end # EWS -end # Viewpoint + end + end +end diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index 8af462fa..6a0f023a 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -1365,5 +1365,5 @@ def format_time(time) raise EwsBadArgumentError, "Invalid Time argument (#{time})" end end - end # EwsBuilder -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_response.rb b/lib/ews/soap/ews_response.rb index 792f16ec..e75508fd 100644 --- a/lib/ews/soap/ews_response.rb +++ b/lib/ews/soap/ews_response.rb @@ -70,5 +70,5 @@ def class_by_name(cname) rescue NameError ResponseMessage end - end # EwsSoapResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_soap_availability_response.rb b/lib/ews/soap/ews_soap_availability_response.rb index 34807bf8..5bfa9c1d 100644 --- a/lib/ews/soap/ews_soap_availability_response.rb +++ b/lib/ews/soap/ews_soap_availability_response.rb @@ -49,5 +49,5 @@ def simplify! body[0][key] = body[0][key][:elems].inject(:merge) response_message[:elems] = response_message[:elems].inject(:merge) end - end # EwsSoapAvailabilityResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_soap_free_busy_response.rb b/lib/ews/soap/ews_soap_free_busy_response.rb index 5b61789c..33ae866d 100644 --- a/lib/ews/soap/ews_soap_free_busy_response.rb +++ b/lib/ews/soap/ews_soap_free_busy_response.rb @@ -110,5 +110,5 @@ def find_in_hash_list(collection, key) result = collection.find { |hsh| hsh.keys.include?(key) } result ? result[key] : nil end - end # EwsSoapFreeBusyResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_soap_response.rb b/lib/ews/soap/ews_soap_response.rb index 07a10a0a..ecdf8768 100644 --- a/lib/ews/soap/ews_soap_response.rb +++ b/lib/ews/soap/ews_soap_response.rb @@ -92,5 +92,5 @@ def guard_hash(hsh, keys) guard_hash hsh[key], keys end end - end # EwsSoapResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_soap_room_response.rb b/lib/ews/soap/ews_soap_room_response.rb index 6f927f1d..cb00ff1f 100644 --- a/lib/ews/soap/ews_soap_room_response.rb +++ b/lib/ews/soap/ews_soap_room_response.rb @@ -44,5 +44,5 @@ def simplify! rm[key][:elems] = rm[key][:elems].inject(&:merge) end end - end # EwsSoapRoomResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/ews_soap_roomlist_response.rb b/lib/ews/soap/ews_soap_roomlist_response.rb index 54edb2e6..9a855558 100644 --- a/lib/ews/soap/ews_soap_roomlist_response.rb +++ b/lib/ews/soap/ews_soap_roomlist_response.rb @@ -44,5 +44,5 @@ def simplify! rm[key][:elems] = rm[key][:elems].inject(&:merge) end end - end # EwsSoapRoomlistResponse -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/exchange_availability.rb b/lib/ews/soap/exchange_availability.rb index b491eadc..454ad529 100644 --- a/lib/ews/soap/exchange_availability.rb +++ b/lib/ews/soap/exchange_availability.rb @@ -54,5 +54,5 @@ def set_user_oof_settings(opts) } do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - end # ExchangeAvailability + end end diff --git a/lib/ews/soap/exchange_data_services.rb b/lib/ews/soap/exchange_data_services.rb index 94bd1a86..a846183c 100644 --- a/lib/ews/soap/exchange_data_services.rb +++ b/lib/ews/soap/exchange_data_services.rb @@ -753,5 +753,5 @@ def convert_id(opts) } do_soap_request(req, response_class: EwsResponse) end - end # ExchangeDataServices + end end diff --git a/lib/ews/soap/exchange_notification.rb b/lib/ews/soap/exchange_notification.rb index d876f881..f1e09f06 100644 --- a/lib/ews/soap/exchange_notification.rb +++ b/lib/ews/soap/exchange_notification.rb @@ -132,5 +132,5 @@ def push_subscribe_folder(folder, evtypes, url, status_frequency = nil, watermar psr[:watermark] = watermark if watermark subscribe([{ push_subscription_request: psr }]) end - end # ExchangeNotification + end end diff --git a/lib/ews/soap/exchange_synchronization.rb b/lib/ews/soap/exchange_synchronization.rb index 95ac73b1..01e47b26 100644 --- a/lib/ews/soap/exchange_synchronization.rb +++ b/lib/ews/soap/exchange_synchronization.rb @@ -84,5 +84,5 @@ def sync_folder_items(opts) } do_soap_request(req, response_class: EwsResponse) end - end # ExchangeSynchronization + end end diff --git a/lib/ews/soap/exchange_user_configuration.rb b/lib/ews/soap/exchange_user_configuration.rb index 27b74830..a8223e31 100644 --- a/lib/ews/soap/exchange_user_configuration.rb +++ b/lib/ews/soap/exchange_user_configuration.rb @@ -27,5 +27,5 @@ def get_user_configuration(opts) } do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - end # ExchangeUserConfiguration + end end diff --git a/lib/ews/soap/exchange_web_service.rb b/lib/ews/soap/exchange_web_service.rb index 2109c256..599c532d 100644 --- a/lib/ews/soap/exchange_web_service.rb +++ b/lib/ews/soap/exchange_web_service.rb @@ -258,5 +258,5 @@ def build_soap!(&block) opts[:time_zone_context] = @time_zone_context if @time_zone_context EwsBuilder.new.build!(opts, &block) end - end # class ExchangeWebService -end # Viewpoint + end +end diff --git a/lib/ews/soap/parsers/ews_parser.rb b/lib/ews/soap/parsers/ews_parser.rb index 84cabfa3..90b79eba 100644 --- a/lib/ews/soap/parsers/ews_parser.rb +++ b/lib/ews/soap/parsers/ews_parser.rb @@ -37,5 +37,5 @@ def parse(opts = {}) def sax_parser @parser ||= Nokogiri::XML::SAX::Parser.new(@sax_doc) end - end # EwsParser -end # Viewpoint + end +end diff --git a/lib/ews/soap/response_message.rb b/lib/ews/soap/response_message.rb index df5a2c42..f8808714 100644 --- a/lib/ews/soap/response_message.rb +++ b/lib/ews/soap/response_message.rb @@ -63,7 +63,7 @@ def safe_hash_access(hsh, keys) end end end -end # Viewpoint::EWS::SOAP +end require_relative './responses/create_item_response_message' require_relative './responses/create_attachment_response_message' diff --git a/lib/ews/soap/responses/create_attachment_response_message.rb b/lib/ews/soap/responses/create_attachment_response_message.rb index d16906ce..b0df1cf1 100644 --- a/lib/ews/soap/responses/create_attachment_response_message.rb +++ b/lib/ews/soap/responses/create_attachment_response_message.rb @@ -37,5 +37,5 @@ def parse_attachments(att) klass.new(item, a[type]) end end - end # CreateAttachmentResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/create_item_response_message.rb b/lib/ews/soap/responses/create_item_response_message.rb index abcfd750..1e283cda 100644 --- a/lib/ews/soap/responses/create_item_response_message.rb +++ b/lib/ews/soap/responses/create_item_response_message.rb @@ -17,5 +17,5 @@ module Viewpoint::EWS::SOAP class CreateItemResponseMessage < ResponseMessage - end # CreateItemResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/find_item_response_message.rb b/lib/ews/soap/responses/find_item_response_message.rb index c002e610..10f73b04 100644 --- a/lib/ews/soap/responses/find_item_response_message.rb +++ b/lib/ews/soap/responses/find_item_response_message.rb @@ -67,5 +67,5 @@ def root_folder rf = safe_hash_access message, %i[elems root_folder] @root_folder = rf.nil? ? nil : RootFolder.new(rf) end - end # FindItemResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/get_events_response_message.rb b/lib/ews/soap/responses/get_events_response_message.rb index e1f48273..c0f5b7ba 100644 --- a/lib/ews/soap/responses/get_events_response_message.rb +++ b/lib/ews/soap/responses/get_events_response_message.rb @@ -44,5 +44,5 @@ def more_events? def events notification[3..-1] end - end # GetEventsResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/send_notification_response_message.rb b/lib/ews/soap/responses/send_notification_response_message.rb index 61947b01..83fe909f 100644 --- a/lib/ews/soap/responses/send_notification_response_message.rb +++ b/lib/ews/soap/responses/send_notification_response_message.rb @@ -51,5 +51,5 @@ def events klass.new(nil, ev[type]) } end - end # SendNotificationResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/subscribe_response_message.rb b/lib/ews/soap/responses/subscribe_response_message.rb index 2945b0bc..f0987702 100644 --- a/lib/ews/soap/responses/subscribe_response_message.rb +++ b/lib/ews/soap/responses/subscribe_response_message.rb @@ -28,5 +28,5 @@ def subscription_id def watermark safe_hash_access subscription, %i[watermark text] end - end # SubscribeResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb index 8e631d2d..653a369a 100644 --- a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb @@ -29,5 +29,5 @@ def includes_last_folder_in_range? def changes safe_hash_access(message, %i[elems changes elems]) || [] end - end # SyncFolderHierarchyResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/soap/responses/sync_folder_items_response_message.rb b/lib/ews/soap/responses/sync_folder_items_response_message.rb index a64f1273..2b4a5de0 100644 --- a/lib/ews/soap/responses/sync_folder_items_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_items_response_message.rb @@ -29,5 +29,5 @@ def includes_last_item_in_range? def changes safe_hash_access(message, %i[elems changes elems]) || [] end - end # SyncFolderItemsResponseMessage -end # Viewpoint::EWS::SOAP + end +end diff --git a/lib/ews/types/attendee.rb b/lib/ews/types/attendee.rb index 47cade45..09a8e27c 100644 --- a/lib/ews/types/attendee.rb +++ b/lib/ews/types/attendee.rb @@ -20,5 +20,5 @@ module Viewpoint::EWS::Types # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs # @todo Design a Class method that resolves to an Array of MailboxUsers class Attendee < MailboxUser - end # Attendee -end # Viewpoint::EWS::Types + end +end diff --git a/lib/ews/types/mailbox_user.rb b/lib/ews/types/mailbox_user.rb index 34828920..71e017d8 100644 --- a/lib/ews/types/mailbox_user.rb +++ b/lib/ews/types/mailbox_user.rb @@ -146,5 +146,5 @@ def key_types def key_alias @key_alias ||= super.merge(MAILBOX_KEY_ALIAS) end - end # MailboxUser -end # Viewpoint::EWS::Types + end +end diff --git a/lib/ews/types/out_of_office.rb b/lib/ews/types/out_of_office.rb index 167b04a6..a67a026c 100644 --- a/lib/ews/types/out_of_office.rb +++ b/lib/ews/types/out_of_office.rb @@ -139,5 +139,5 @@ def simplify! @ews_item[:oof_settings] = oof_settings @ews_item[:allow_external_oof] = @ews_item[:allow_external_oof][:text] end - end # OutOfOffice + end end diff --git a/lib/viewpoint/logging.rb b/lib/viewpoint/logging.rb index 49ce9882..95e4c495 100644 --- a/lib/viewpoint/logging.rb +++ b/lib/viewpoint/logging.rb @@ -22,5 +22,5 @@ module EWS def self.root_logger Logging.logger.root end - end # EWS + end end diff --git a/lib/viewpoint/logging/config.rb b/lib/viewpoint/logging/config.rb index 76d9aad9..ca2aa08b 100644 --- a/lib/viewpoint/logging/config.rb +++ b/lib/viewpoint/logging/config.rb @@ -19,5 +19,5 @@ module Viewpoint module EWS Logging.logger.root.level = :debug Logging.logger.root.appenders = Logging.appenders.stdout - end # EWS + end end diff --git a/lib/viewpoint/string_utils.rb b/lib/viewpoint/string_utils.rb index acc6c282..75641665 100644 --- a/lib/viewpoint/string_utils.rb +++ b/lib/viewpoint/string_utils.rb @@ -70,5 +70,5 @@ def iso8601_duration_to_seconds(input) duration += match_data[:minutes].to_i * 60 duration + match_data[:seconds].to_i end - end # StringUtils -end # Viewpoint + end +end From d0835323a5d98d4bd7f8e4affeaa4dca74263258 Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:57:02 +0000 Subject: [PATCH 04/12] Lint: nested module/class definitions (Style/ClassAndModuleChildren) --- Gemfile | 1 + Guardfile | 1 + Rakefile | 1 + lib/ews/calendar_accessors.rb | 25 +- lib/ews/connection.rb | 217 +- lib/ews/connection_helper.rb | 29 +- lib/ews/convert_accessors.rb | 63 +- lib/ews/errors.rb | 75 +- lib/ews/ews_client.rb | 157 +- lib/ews/exceptions/exceptions.rb | 59 +- lib/ews/folder_accessors.rb | 436 ++-- lib/ews/impersonation.rb | 51 +- lib/ews/item_accessors.rb | 395 +-- lib/ews/mailbox_accessors.rb | 125 +- lib/ews/meeting_accessors.rb | 67 +- lib/ews/message_accessors.rb | 129 +- lib/ews/push_subscription_accessors.rb | 21 +- lib/ews/room_accessors.rb | 43 +- lib/ews/roomlist_accessors.rb | 41 +- lib/ews/soap.rb | 1 + lib/ews/soap/builders/ews_builder.rb | 2307 +++++++++-------- lib/ews/soap/ews_response.rb | 93 +- .../soap/ews_soap_availability_response.rb | 59 +- lib/ews/soap/ews_soap_free_busy_response.rb | 191 +- lib/ews/soap/ews_soap_response.rb | 129 +- lib/ews/soap/ews_soap_room_response.rb | 49 +- lib/ews/soap/ews_soap_roomlist_response.rb | 49 +- lib/ews/soap/exchange_availability.rb | 99 +- lib/ews/soap/exchange_data_services.rb | 1379 +++++----- lib/ews/soap/exchange_notification.rb | 209 +- lib/ews/soap/exchange_synchronization.rb | 129 +- lib/ews/soap/exchange_time_zones.rb | 81 +- lib/ews/soap/exchange_user_configuration.rb | 53 +- lib/ews/soap/exchange_web_service.rb | 419 +-- lib/ews/soap/parsers/ews_parser.rb | 39 +- lib/ews/soap/parsers/ews_sax_document.rb | 89 +- lib/ews/soap/response_message.rb | 75 +- .../create_attachment_response_message.rb | 37 +- .../responses/create_item_response_message.rb | 9 +- .../responses/find_item_response_message.rb | 81 +- .../responses/get_events_response_message.rb | 49 +- .../send_notification_response_message.rb | 63 +- .../responses/subscribe_response_message.rb | 25 +- .../sync_folder_hierarchy_response_message.rb | 27 +- .../sync_folder_items_response_message.rb | 27 +- lib/ews/templates/calendar_item.rb | 127 +- lib/ews/templates/forward_item.rb | 33 +- lib/ews/templates/message.rb | 111 +- lib/ews/templates/reply_to_item.rb | 35 +- lib/ews/templates/task.rb | 115 +- lib/ews/types.rb | 279 +- lib/ews/types/attachment.rb | 93 +- lib/ews/types/attendee.rb | 15 +- lib/ews/types/calendar_folder.rb | 105 +- lib/ews/types/calendar_item.rb | 257 +- lib/ews/types/contact.rb | 15 +- lib/ews/types/contacts_folder.rb | 15 +- lib/ews/types/copied_event.rb | 41 +- lib/ews/types/created_event.rb | 9 +- lib/ews/types/deleted_event.rb | 9 +- lib/ews/types/distribution_list.rb | 15 +- lib/ews/types/event.rb | 79 +- .../types/export_items_response_message.rb | 83 +- lib/ews/types/file_attachment.rb | 64 +- lib/ews/types/folder.rb | 105 +- lib/ews/types/free_busy_changed_event.rb | 9 +- lib/ews/types/generic_folder.rb | 647 ++--- lib/ews/types/item.rb | 767 +++--- lib/ews/types/item_attachment.rb | 102 +- lib/ews/types/item_field_uri_map.rb | 1 + lib/ews/types/mailbox_user.rb | 259 +- lib/ews/types/meeting_cancellation.rb | 15 +- lib/ews/types/meeting_message.rb | 15 +- lib/ews/types/meeting_request.rb | 15 +- lib/ews/types/meeting_response.rb | 15 +- lib/ews/types/message.rb | 15 +- lib/ews/types/modified_event.rb | 33 +- lib/ews/types/moved_event.rb | 41 +- lib/ews/types/new_mail_event.rb | 9 +- lib/ews/types/out_of_office.rb | 249 +- lib/ews/types/post_item.rb | 15 +- lib/ews/types/search_folder.rb | 15 +- lib/ews/types/status_event.rb | 27 +- lib/ews/types/task.rb | 67 +- lib/ews/types/tasks_folder.rb | 51 +- lib/viewpoint.rb | 1 + lib/viewpoint/logging.rb | 1 + lib/viewpoint/logging/config.rb | 1 + lib/viewpoint/string_utils.rb | 1 + spec/ews/ews_client_spec.rb | 1 + spec/ews/types/calendar_item_spec.rb | 1 + spec/spec_helper.rb | 1 + spec/unit/dodgy_file_spec.rb | 1 + spec/unit/ews_folder_operations_spec.rb | 1 + spec/unit/ews_parser_spec.rb | 1 + spec/unit/ews_rooms_operations_spec.rb | 1 + spec/unit/ews_soap_free_busy_response_spec.rb | 1 + spec/unit/folder_accessors_spec.rb | 1 + spec/unit/item_accessors_spec.rb | 1 + spec/unit/mailbox_accessors_spec.rb | 1 + spec/unit/meeting_accessors_spec.rb | 1 + spec/unit/soap/builders/ews_builder_spec.rb | 1 + spec/viewpoint/string_utils_spec.rb | 1 + spec/xml_matcher.rb | 1 + viewpoint.gemspec | 1 + 105 files changed, 6055 insertions(+), 5641 deletions(-) diff --git a/Gemfile b/Gemfile index bae48233..a9556bf9 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,5 @@ # frozen_string_literal: true + source 'https://rubygems.org/' gemspec diff --git a/Guardfile b/Guardfile index 11d274a8..44371195 100644 --- a/Guardfile +++ b/Guardfile @@ -1,4 +1,5 @@ # frozen_string_literal: true + # A sample Guardfile # More info at https://github.com/guard/guard#readme diff --git a/Rakefile b/Rakefile index 8009d8c5..45433e62 100644 --- a/Rakefile +++ b/Rakefile @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'rubygems' require 'bundler' diff --git a/lib/ews/calendar_accessors.rb b/lib/ews/calendar_accessors.rb index e016069c..8152c8ae 100644 --- a/lib/ews/calendar_accessors.rb +++ b/lib/ews/calendar_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Mark McCahill @@ -15,18 +16,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::CalendarAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module CalendarAccessors + include Viewpoint::EWS - def event_busy_type(the_event) - the_event[:calendar_event][:elems][2][:busy_type][:text] - end + def event_busy_type(the_event) + the_event[:calendar_event][:elems][2][:busy_type][:text] + end - def event_start_time(the_event) - the_event[:calendar_event][:elems][0][:start_time][:text] - end + def event_start_time(the_event) + the_event[:calendar_event][:elems][0][:start_time][:text] + end - def event_end_time(the_event) - the_event[:calendar_event][:elems][1][:end_time][:text] + def event_end_time(the_event) + the_event[:calendar_event][:elems][1][:end_time][:text] + end + end end end diff --git a/lib/ews/connection.rb b/lib/ews/connection.rb index 3bf6ac5c..77bab938 100644 --- a/lib/ews/connection.rb +++ b/lib/ews/connection.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -16,125 +17,129 @@ # limitations under the License. require 'httpclient' -class Viewpoint::EWS::Connection - include Viewpoint::EWS::ConnectionHelper - include Viewpoint::EWS - - attr_reader :endpoint - - @@supported_httpclient_opts = %i[agent_name default_header] - - # @param [String] endpoint the URL of the web service. - # @example https:///ews/Exchange.asmx - # @param [Hash] opts Misc config options (mostly for development) - # @option opts [Fixnum] :ssl_verify_mode - # @option opts [Fixnum] :receive_timeout override the default receive timeout - # seconds - # @option opts [Fixnum] :connect_timeout override the default connect timeout - # seconds - # @option opts [Array] :trust_ca an array of hashed dir paths or a file - # @option opts [String] :user_agent the http user agent to use in all requests - def initialize(endpoint, opts = {}) - @log = Logging.logger[self.class.name.to_s.to_sym] - - httpclient_opts = opts.slice(*@@supported_httpclient_opts) - @httpcli = HTTPClient.new(**httpclient_opts) - - if opts[:trust_ca] - @httpcli.ssl_config.clear_cert_store - opts[:trust_ca].each do |ca| - @httpcli.ssl_config.add_trust_ca ca +module Viewpoint + module EWS + class Connection + include Viewpoint::EWS::ConnectionHelper + include Viewpoint::EWS + + attr_reader :endpoint + + @@supported_httpclient_opts = %i[agent_name default_header] + + # @param [String] endpoint the URL of the web service. + # @example https:///ews/Exchange.asmx + # @param [Hash] opts Misc config options (mostly for development) + # @option opts [Fixnum] :ssl_verify_mode + # @option opts [Fixnum] :receive_timeout override the default receive timeout + # seconds + # @option opts [Fixnum] :connect_timeout override the default connect timeout + # seconds + # @option opts [Array] :trust_ca an array of hashed dir paths or a file + # @option opts [String] :user_agent the http user agent to use in all requests + def initialize(endpoint, opts = {}) + @log = Logging.logger[self.class.name.to_s.to_sym] + + httpclient_opts = opts.slice(*@@supported_httpclient_opts) + @httpcli = HTTPClient.new(**httpclient_opts) + + if opts[:trust_ca] + @httpcli.ssl_config.clear_cert_store + opts[:trust_ca].each do |ca| + @httpcli.ssl_config.add_trust_ca ca + end + end + + @httpcli.ssl_config.verify_mode = opts[:ssl_verify_mode] if opts[:ssl_verify_mode] + @httpcli.ssl_config.ssl_version = opts[:ssl_version] if opts[:ssl_version] + # Up the keep-alive so we don't have to do the NTLM dance as often. + @httpcli.keep_alive_timeout = 60 + @httpcli.receive_timeout = opts[:receive_timeout] if opts[:receive_timeout] + @httpcli.connect_timeout = opts[:connect_timeout] if opts[:connect_timeout] + @endpoint = endpoint end - end - @httpcli.ssl_config.verify_mode = opts[:ssl_verify_mode] if opts[:ssl_verify_mode] - @httpcli.ssl_config.ssl_version = opts[:ssl_version] if opts[:ssl_version] - # Up the keep-alive so we don't have to do the NTLM dance as often. - @httpcli.keep_alive_timeout = 60 - @httpcli.receive_timeout = opts[:receive_timeout] if opts[:receive_timeout] - @httpcli.connect_timeout = opts[:connect_timeout] if opts[:connect_timeout] - @endpoint = endpoint - end - - def set_auth(user, pass) - @httpcli.set_auth(@endpoint.to_s, user, pass) - end + def set_auth(user, pass) + @httpcli.set_auth(@endpoint.to_s, user, pass) + end - # Authenticate to the web service. You don't have to do this because - # authentication will happen on the first request if you don't do it here. - # @return [Boolean] true if authentication is successful, false otherwise - def authenticate - get && true - end + # Authenticate to the web service. You don't have to do this because + # authentication will happen on the first request if you don't do it here. + # @return [Boolean] true if authentication is successful, false otherwise + def authenticate + get && true + end - # Every Connection class must have the dispatch method. It is what sends the - # SOAP request to the server and calls the parser method on the EWS instance. - # - # This was originally in the ExchangeWebService class but it was added here - # to make the processing chain easier to modify. For example, it allows the - # reactor pattern to handle the request with a callback. - # @param ews [Viewpoint::EWS::SOAP::ExchangeWebService] used to call - # #parse_soap_response - # @param soapmsg [String] - # @param opts [Hash] misc opts for handling the Response - def dispatch(ews, soapmsg, opts) - respmsg = post(soapmsg) - @log.debug <<-EOF.gsub(/^ {6}/, '') + # Every Connection class must have the dispatch method. It is what sends the + # SOAP request to the server and calls the parser method on the EWS instance. + # + # This was originally in the ExchangeWebService class but it was added here + # to make the processing chain easier to modify. For example, it allows the + # reactor pattern to handle the request with a callback. + # @param ews [Viewpoint::EWS::SOAP::ExchangeWebService] used to call + # #parse_soap_response + # @param soapmsg [String] + # @param opts [Hash] misc opts for handling the Response + def dispatch(ews, soapmsg, opts) + respmsg = post(soapmsg) + @log.debug <<-EOF.gsub(/^ {6}/, '') Received SOAP Response: ---------------- #{Nokogiri::XML(respmsg).to_xml} ---------------- - EOF - opts[:raw_response] ? respmsg : ews.parse_soap_response(respmsg, opts) - end - - # Send a GET to the web service - # @return [String] If the request is successful (200) it returns the body of - # the response. - def get - check_response(@httpcli.get(@endpoint)) - end + EOF + opts[:raw_response] ? respmsg : ews.parse_soap_response(respmsg, opts) + end - # Send a POST to the web service - # @return [String] If the request is successful (200) it returns the body of - # the response. - def post(xmldoc) - headers = { 'Content-Type' => 'text/xml' } - check_response(@httpcli.post(@endpoint, xmldoc, headers)) - end + # Send a GET to the web service + # @return [String] If the request is successful (200) it returns the body of + # the response. + def get + check_response(@httpcli.get(@endpoint)) + end - private - - def check_response(resp) - case resp.status - when 200 - resp.body - when 302 - # @todo redirect - raise Errors::UnhandledResponseError.new('Unhandled HTTP Redirect', resp) - when 401 - raise Errors::UnauthorizedResponseError.new('Unauthorized request', resp) - when 500 - unless resp.headers['Content-Type'] =~ /xml/ - raise Errors::ServerError.new("Internal Server Error. Message: #{resp.body}", resp) + # Send a POST to the web service + # @return [String] If the request is successful (200) it returns the body of + # the response. + def post(xmldoc) + headers = { 'Content-Type' => 'text/xml' } + check_response(@httpcli.post(@endpoint, xmldoc, headers)) end - err_string, err_code = parse_soap_error(resp.body) - raise Errors::SoapResponseError.new("SOAP Error: Message: #{err_string} Code: #{err_code}", resp, err_code, - err_string) + private + + def check_response(resp) + case resp.status + when 200 + resp.body + when 302 + # @todo redirect + raise Errors::UnhandledResponseError.new('Unhandled HTTP Redirect', resp) + when 401 + raise Errors::UnauthorizedResponseError.new('Unauthorized request', resp) + when 500 + unless resp.headers['Content-Type'] =~ /xml/ + raise Errors::ServerError.new("Internal Server Error. Message: #{resp.body}", resp) + end + + err_string, err_code = parse_soap_error(resp.body) + raise Errors::SoapResponseError.new("SOAP Error: Message: #{err_string} Code: #{err_code}", resp, err_code, + err_string) + + else + raise Errors::ResponseError.new("HTTP Error Code: #{resp.status}, Msg: #{resp.body}", resp) + end + end - else - raise Errors::ResponseError.new("HTTP Error Code: #{resp.status}, Msg: #{resp.body}", resp) + # @param [String] xml to parse the errors from. + def parse_soap_error(xml) + ndoc = Nokogiri::XML(xml) + ns = ndoc.collect_namespaces + err_string = ndoc.xpath('//faultstring', ns).text + err_code = ndoc.xpath('//faultcode', ns).text + @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" + [err_string, err_code] + end end end - - # @param [String] xml to parse the errors from. - def parse_soap_error(xml) - ndoc = Nokogiri::XML(xml) - ns = ndoc.collect_namespaces - err_string = ndoc.xpath('//faultstring', ns).text - err_code = ndoc.xpath('//faultcode', ns).text - @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" - [err_string, err_code] - end end diff --git a/lib/ews/connection_helper.rb b/lib/ews/connection_helper.rb index 171006dc..bda78c74 100644 --- a/lib/ews/connection_helper.rb +++ b/lib/ews/connection_helper.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,18 +16,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::ConnectionHelper - def init_logging! - @log = Logging.logger[self.class.name.to_s.to_sym] - end +module Viewpoint + module EWS + module ConnectionHelper + def init_logging! + @log = Logging.logger[self.class.name.to_s.to_sym] + end - # @param [String] xml to parse the errors from. - def parse_soap_error(xml) - ndoc = Nokogiri::XML(xml) - ns = ndoc.collect_namespaces - err_string = ndoc.xpath('//faultstring', ns).text - err_code = ndoc.xpath('//faultcode', ns).text - @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" - [err_string, err_code] + # @param [String] xml to parse the errors from. + def parse_soap_error(xml) + ndoc = Nokogiri::XML(xml) + ns = ndoc.collect_namespaces + err_string = ndoc.xpath('//faultstring', ns).text + err_code = ndoc.xpath('//faultcode', ns).text + @log.debug "Internal SOAP error. Message: #{err_string}, Code: #{err_code}" + [err_string, err_code] + end + end end end diff --git a/lib/ews/convert_accessors.rb b/lib/ews/convert_accessors.rb index f71a665a..e357ae76 100644 --- a/lib/ews/convert_accessors.rb +++ b/lib/ews/convert_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Dan Wanek @@ -14,41 +15,45 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::ConvertAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module ConvertAccessors + include Viewpoint::EWS - # This is a class method that converts identifiers between formats. - # @param [String] id The id to be converted - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :format :ews_legacy_id/:ews_id/:entry_id/:hex_entry_id/:store_id/:owa_id - # @option opts [Symbol] :destination_format :ews_legacy_id/:ews_id/:entry_id/:hex_entry_id/:store_id/:owa_id - # @option opts [String] :mailbox Mailbox, if required - # @return [EwsResponse] Returns an EwsResponse containing the convert response message + # This is a class method that converts identifiers between formats. + # @param [String] id The id to be converted + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :format :ews_legacy_id/:ews_id/:entry_id/:hex_entry_id/:store_id/:owa_id + # @option opts [Symbol] :destination_format :ews_legacy_id/:ews_id/:entry_id/:hex_entry_id/:store_id/:owa_id + # @option opts [String] :mailbox Mailbox, if required + # @return [EwsResponse] Returns an EwsResponse containing the convert response message - def convert_id(id, opts = {}) - args = convert_id_args(id, opts.clone) - obj = OpenStruct.new(opts: args) - yield obj if block_given? - resp = ews.convert_id(args) - convert_id_parser(resp) - end + def convert_id(id, opts = {}) + args = convert_id_args(id, opts.clone) + obj = OpenStruct.new(opts: args) + yield obj if block_given? + resp = ews.convert_id(args) + convert_id_parser(resp) + end - private + private - def convert_id_args(id, opts) - { id: id }.merge opts - end + def convert_id_args(id, opts) + { id: id }.merge opts + end - def convert_id_parser(resp) - rm = resp.response_messages[0] + def convert_id_parser(resp) + rm = resp.response_messages[0] - if rm && rm.status == 'Success' - # @todo create custom response class - rm - else - rm.respond_to?(:code) ? rm.code : 'Unknown' - rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' - raise EwsError, "Could not convert id. #{rm.code}: #{rm.message_text}" + if rm && rm.status == 'Success' + # @todo create custom response class + rm + else + rm.respond_to?(:code) ? rm.code : 'Unknown' + rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' + raise EwsError, "Could not convert id. #{rm.code}: #{rm.message_text}" + end + end end end end diff --git a/lib/ews/errors.rb b/lib/ews/errors.rb index c39600fe..c810112b 100644 --- a/lib/ews/errors.rb +++ b/lib/ews/errors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,41 +16,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Errors - class ResponseError < RuntimeError - attr_reader :response - - def initialize(message, response) - super(message) - @response = response - end - - def status - response.status - end - - def body - response.body - end - end - - class UnhandledResponseError < ResponseError - end - - class ServerError < ResponseError - end - - class UnauthorizedResponseError < ResponseError - end - - class SoapResponseError < ResponseError - attr_reader :faultcode, - :faultstring - - def initialize(message, response, faultcode, faultstring) - super(message, response) - @faultcode = faultcode - @faultstring = faultstring +module Viewpoint + module EWS + module Errors + class ResponseError < RuntimeError + attr_reader :response + + def initialize(message, response) + super(message) + @response = response + end + + def status + response.status + end + + def body + response.body + end + end + + class UnhandledResponseError < ResponseError + end + + class ServerError < ResponseError + end + + class UnauthorizedResponseError < ResponseError + end + + class SoapResponseError < ResponseError + attr_reader :faultcode, + :faultstring + + def initialize(message, response, faultcode, faultstring) + super(message, response) + @faultcode = faultcode + @faultstring = faultstring + end + end end end end diff --git a/lib/ews/ews_client.rb b/lib/ews/ews_client.rb index 45729a72..d6802dba 100644 --- a/lib/ews/ews_client.rb +++ b/lib/ews/ews_client.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'ews/folder_accessors' require 'ews/item_accessors' require 'ews/message_accessors' @@ -11,92 +12,94 @@ require 'ews/meeting_accessors' # This class is the glue between the Models and the Web Service. -class Viewpoint::EWSClient - include Viewpoint::EWS - include Viewpoint::EWS::FolderAccessors - include Viewpoint::EWS::ItemAccessors - include Viewpoint::EWS::MessageAccessors - include Viewpoint::EWS::MailboxAccessors - include Viewpoint::EWS::PushSubscriptionAccessors - include Viewpoint::EWS::CalendarAccessors - include Viewpoint::EWS::RoomAccessors - include Viewpoint::EWS::RoomlistAccessors - include Viewpoint::EWS::ConvertAccessors - include Viewpoint::EWS::MeetingAccessors - include Viewpoint::StringUtils +module Viewpoint + class EWSClient + include Viewpoint::EWS + include Viewpoint::EWS::FolderAccessors + include Viewpoint::EWS::ItemAccessors + include Viewpoint::EWS::MessageAccessors + include Viewpoint::EWS::MailboxAccessors + include Viewpoint::EWS::PushSubscriptionAccessors + include Viewpoint::EWS::CalendarAccessors + include Viewpoint::EWS::RoomAccessors + include Viewpoint::EWS::RoomlistAccessors + include Viewpoint::EWS::ConvertAccessors + include Viewpoint::EWS::MeetingAccessors + include Viewpoint::StringUtils - # The instance of Viewpoint::EWS::SOAP::ExchangeWebService - attr_reader :ews, :endpoint, :username + # The instance of Viewpoint::EWS::SOAP::ExchangeWebService + attr_reader :ews, :endpoint, :username - # Initialize the EWSClient instance. - # @param [String] endpoint The EWS endpoint we will be connecting to - # @param [String] user The user to authenticate as. If you are using - # NTLM or Negotiate authentication you do not need to pass this parameter. - # @param [String] pass The user password. If you are using NTLM or - # Negotiate authentication you do not need to pass this parameter. - # @param [Hash] opts Various options to pass to the backends - # @option opts [String] :server_version The Exchange server version to - # target. See the VERSION_* constants in - # Viewpoint::EWS::SOAP::ExchangeWebService. - # @option opts [Object] :http_class specify an alternate HTTP connection class. - # @option opts [Hash] :http_opts options to pass to the connection - def initialize(endpoint, username, password, opts = {}) - # dup all. @see ticket https://github.com/zenchild/Viewpoint/issues/68 - @endpoint = endpoint.dup - @username = username.dup - password = password.dup - opts = opts.dup - http_klass = opts[:http_class] || Viewpoint::EWS::Connection - con = http_klass.new(endpoint, opts[:http_opts] || {}) - con.set_auth @username, password - @ews = SOAP::ExchangeWebService.new(con, opts) - end + # Initialize the EWSClient instance. + # @param [String] endpoint The EWS endpoint we will be connecting to + # @param [String] user The user to authenticate as. If you are using + # NTLM or Negotiate authentication you do not need to pass this parameter. + # @param [String] pass The user password. If you are using NTLM or + # Negotiate authentication you do not need to pass this parameter. + # @param [Hash] opts Various options to pass to the backends + # @option opts [String] :server_version The Exchange server version to + # target. See the VERSION_* constants in + # Viewpoint::EWS::SOAP::ExchangeWebService. + # @option opts [Object] :http_class specify an alternate HTTP connection class. + # @option opts [Hash] :http_opts options to pass to the connection + def initialize(endpoint, username, password, opts = {}) + # dup all. @see ticket https://github.com/zenchild/Viewpoint/issues/68 + @endpoint = endpoint.dup + @username = username.dup + password = password.dup + opts = opts.dup + http_klass = opts[:http_class] || Viewpoint::EWS::Connection + con = http_klass.new(endpoint, opts[:http_opts] || {}) + con.set_auth @username, password + @ews = SOAP::ExchangeWebService.new(con, opts) + end - # @param deepen [Boolean] true to autodeepen, false otherwise - # @param behavior [Symbol] :raise, :nil When setting autodeepen to false you - # can choose what the behavior is when an attribute does not exist. The - # default is to raise a EwsMinimalObjectError. - def set_auto_deepen(deepen, behavior = :raise) - if deepen - ews.auto_deepen = true - else - behavior = %i[raise nil].include?(behavior) ? behavior : :raise - ews.no_auto_deepen_behavior = behavior - ews.auto_deepen = false + # @param deepen [Boolean] true to autodeepen, false otherwise + # @param behavior [Symbol] :raise, :nil When setting autodeepen to false you + # can choose what the behavior is when an attribute does not exist. The + # default is to raise a EwsMinimalObjectError. + def set_auto_deepen(deepen, behavior = :raise) + if deepen + ews.auto_deepen = true + else + behavior = %i[raise nil].include?(behavior) ? behavior : :raise + ews.no_auto_deepen_behavior = behavior + ews.auto_deepen = false + end end - end - def auto_deepen=(deepen) - set_auto_deepen deepen - end + def auto_deepen=(deepen) + set_auto_deepen deepen + end - # Specify a default time zone context for all time attributes - # @param id [String] Identifier of a Microsoft well known time zone (e.g: 'UTC', 'W. Europe Standard Time') - # @note A list of time zones known by the server can be requested via {EWS::SOAP::ExchangeTimeZones#get_time_zones} - def set_time_zone(microsoft_time_zone_id) - ews.set_time_zone_context microsoft_time_zone_id - end + # Specify a default time zone context for all time attributes + # @param id [String] Identifier of a Microsoft well known time zone (e.g: 'UTC', 'W. Europe Standard Time') + # @note A list of time zones known by the server can be requested via {EWS::SOAP::ExchangeTimeZones#get_time_zones} + def set_time_zone(microsoft_time_zone_id) + ews.set_time_zone_context microsoft_time_zone_id + end - private + private - # This method also exists in EWS::Types, but there is a lot of other stuff - # in there that I didn't want to include directly in this class. - def class_by_name(cname) - cname = camel_case(cname) if cname.instance_of? Symbol - Viewpoint::EWS::Types.const_get(cname) - end + # This method also exists in EWS::Types, but there is a lot of other stuff + # in there that I didn't want to include directly in this class. + def class_by_name(cname) + cname = camel_case(cname) if cname.instance_of? Symbol + Viewpoint::EWS::Types.const_get(cname) + end - # Used for multiple accessors - def merge_restrictions!(obj, merge_type = :and) - if obj.opts[:restriction] && !obj.opts[:restriction].empty? && !obj.restriction.empty? - obj.opts[:restriction] = { - merge_type => [ - obj.opts.delete(:restriction), - obj.restriction - ] - } - elsif !obj.restriction.empty? - obj.opts[:restriction] = obj.restriction + # Used for multiple accessors + def merge_restrictions!(obj, merge_type = :and) + if obj.opts[:restriction] && !obj.opts[:restriction].empty? && !obj.restriction.empty? + obj.opts[:restriction] = { + merge_type => [ + obj.opts.delete(:restriction), + obj.restriction + ] + } + elsif !obj.restriction.empty? + obj.opts[:restriction] = obj.restriction + end end end end diff --git a/lib/ews/exceptions/exceptions.rb b/lib/ews/exceptions/exceptions.rb index d0beed01..d04aad18 100644 --- a/lib/ews/exceptions/exceptions.rb +++ b/lib/ews/exceptions/exceptions.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -14,45 +15,47 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS - # Generic Ews Error - class EwsError < StandardError; end +module Viewpoint + module EWS + # Generic Ews Error + class EwsError < StandardError; end - # Raise when authentication/authorization issues occur. - class EwsLoginError < EwsError; end + # Raise when authentication/authorization issues occur. + class EwsLoginError < EwsError; end - class EwsSubscriptionError < EwsError; end + class EwsSubscriptionError < EwsError; end - # Raised when a user tries to query a folder subscription after the - # subscription has timed out. - class EwsSubscriptionTimeout < EwsSubscriptionError; end + # Raised when a user tries to query a folder subscription after the + # subscription has timed out. + class EwsSubscriptionTimeout < EwsSubscriptionError; end - # Represents a function in EWS that is not yet implemented in Viewpoint - class EwsNotImplemented < EwsError; end + # Represents a function in EWS that is not yet implemented in Viewpoint + class EwsNotImplemented < EwsError; end - # Raised when an method is called in the wrong way - class EwsBadArgumentError < EwsError; end + # Raised when an method is called in the wrong way + class EwsBadArgumentError < EwsError; end - # Raised when an item that is asked for is not found - class EwsItemNotFound < EwsError; end + # Raised when an item that is asked for is not found + class EwsItemNotFound < EwsError; end - # Raised when a folder that is asked for is not found - class EwsFolderNotFound < EwsError; end + # Raised when a folder that is asked for is not found + class EwsFolderNotFound < EwsError; end - # Raise an Exchange Server version error. This is in case some functionality - # does not exist in a particular Server version but is called. - class EwsServerVersionError < EwsError; end + # Raise an Exchange Server version error. This is in case some functionality + # does not exist in a particular Server version but is called. + class EwsServerVersionError < EwsError; end - # Raised when #auto_deepen == false and a method is called for attributes - # that have not yet been fetched. - class EwsMinimalObjectError < EwsError; end + # Raised when #auto_deepen == false and a method is called for attributes + # that have not yet been fetched. + class EwsMinimalObjectError < EwsError; end - class EwsFrozenObjectError < EwsError; end + class EwsFrozenObjectError < EwsError; end - # Failed to save an object back to the EWS store. - class SaveFailed < EwsError; end + # Failed to save an object back to the EWS store. + class SaveFailed < EwsError; end - class EwsCreateItemError < EwsError; end + class EwsCreateItemError < EwsError; end - class EwsSendItemError < EwsError; end + class EwsSendItemError < EwsError; end + end end diff --git a/lib/ews/folder_accessors.rb b/lib/ews/folder_accessors.rb index b91128d5..b0f2e432 100644 --- a/lib/ews/folder_accessors.rb +++ b/lib/ews/folder_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -14,237 +15,244 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::FolderAccessors - include Viewpoint::EWS - - FOLDER_TYPE_MAP = { - mail: 'IPF.Note', - calendar: 'IPF.Appointment', - task: 'IPF.Task' - } - - # Find subfolders of the passed root folder. If no parameters are passed this - # method will search from the Root folder. - # @param [Hash] opts Misc options to control request - # @option opts [String,Symbol] :root Either a FolderId(String) or a - # DistinguishedFolderId(Symbol) . This is where to start the search from. - # Usually :root,:msgfolderroot, or :publicfoldersroot - # @option opts [Symbol] :traversal :shallow/:deep/:soft_deleted - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @option opts [optional, String] :folder_type an optional folder type to - # limit the search to like 'IPF.Task' - # @return [Array] Returns an Array of Folder or subclasses of Folder - # @raise [EwsError] raised when the backend SOAP method returns an error. - def folders(opts = {}) - opts = opts.clone - args = find_folders_args(opts) - obj = OpenStruct.new(opts: args, restriction: {}) - yield obj if block_given? - merge_restrictions! obj - resp = ews.find_folder(args) - find_folders_parser(resp) - end - alias find_folders folders - - # Get a specific folder by id or symbol - # @param [String,Symbol,Hash] folder_id Either a FolderId(String) or a - # DistinguishedFolderId(Symbol). You can also pass a Hash in the form: - # {id: , change_key: } - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @option opts [String,nil] :act_as User to act on behalf as. This user must - # have been given delegate access to the folder or this operation will fail. - # @raise [EwsError] raised when the backend SOAP method returns an error. - def get_folder(folder_id, opts = {}) - opts = opts.clone - args = get_folder_args(folder_id, opts) - resp = ews.get_folder(args) - get_folder_parser(resp) - end +module Viewpoint + module EWS + module FolderAccessors + include Viewpoint::EWS - # Get a specific folder by its name - # @param [String] name The folder name - # @param [Hash] opts Misc options to control request - # @option opts [String,Symbol] :parent Either a FolderId(String) or a - # DistinguishedFolderId(Symbol) . This is the parent folder. - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @option opts [String,nil] :act_as User to act on behalf as. This user must - # have been given delegate access to the folder or this operation will fail. - # @raise [EwsError] raised when the backend SOAP method returns an error. - def get_folder_by_name(name, opts = {}) - opts = opts.clone - opts[:root] = opts.delete(:parent) - folders(opts) { |obj| - obj.restriction = { - is_equal_to: [ - { field_uRI: { field_uRI: 'folder:DisplayName' } }, - { field_uRI_or_constant: { constant: { value: name } } } - ] + FOLDER_TYPE_MAP = { + mail: 'IPF.Note', + calendar: 'IPF.Appointment', + task: 'IPF.Task' } - }.first - end - # @param [String] name The name of the new folder - # @param [Hash] opts - # @option opts [String,Symbol] :parent Either a FolderId(String) or a - # DistinguishedFolderId(Symbol) . This is the parent folder. - # @option opts [Symbol] :type the type of folder to create. must be one of - # :folder, :calendar, :contacts, :search, or :tasks - # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx - def make_folder(name, opts = {}) - parent = opts[:parent] || :msgfolderroot - resp = ews.create_folder parent_folder_id: { id: parent }, - folders: [{ folder_type(opts[:type]) => { display_name: name } }] - create_folder_parser(resp).first - end - alias mkfolder make_folder - - # Get a specific folder by id or symbol - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @option opts [String,Symbol,Hash] :folder_id You can optionally specify a - # folder_id to limit the hierarchy synchronization to it. It must be a - # FolderId(String), a DistinguishedFolderId(Symbol) or you can pass a Hash - # in the form: {id: , change_key: } - # @option opts [String] :sync_state an optional Base64 encoded SyncState - # String from a previous sync call. - # @yield [Hash] yields the formatted argument Hash for last-minute - # modification before calling the backend EWS method. - # @return [Hash] A hash with the following keys - # :all_synced, whether or not additional calls are needed to get all folders - # :sync_state, the sync state to use for the next call - # and the following optional keys depending on the changes - # :create, :update, :delete - # @raise [EwsError] raised when the backend SOAP method returns an error. - def sync_folders(opts = {}) - opts = opts.clone - args = sync_folders_args(opts) - yield args if block_given? - resp = ews.sync_folder_hierarchy(args) - sync_folders_parser(resp) - end + # Find subfolders of the passed root folder. If no parameters are passed this + # method will search from the Root folder. + # @param [Hash] opts Misc options to control request + # @option opts [String,Symbol] :root Either a FolderId(String) or a + # DistinguishedFolderId(Symbol) . This is where to start the search from. + # Usually :root,:msgfolderroot, or :publicfoldersroot + # @option opts [Symbol] :traversal :shallow/:deep/:soft_deleted + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @option opts [optional, String] :folder_type an optional folder type to + # limit the search to like 'IPF.Task' + # @return [Array] Returns an Array of Folder or subclasses of Folder + # @raise [EwsError] raised when the backend SOAP method returns an error. + def folders(opts = {}) + opts = opts.clone + args = find_folders_args(opts) + obj = OpenStruct.new(opts: args, restriction: {}) + yield obj if block_given? + merge_restrictions! obj + resp = ews.find_folder(args) + find_folders_parser(resp) + end + alias find_folders folders - private - - # Build up the arguements for #find_folders - def find_folders_args(opts) - opts[:root] = opts[:root] || :msgfolderroot - opts[:traversal] = opts[:traversal] || :shallow - opts[:shape] = opts[:shape] || :default - folder_id = { id: opts[:root] } - folder_id[:act_as] = opts[:act_as] if opts[:act_as] - if opts[:folder_type] - restr = { is_equal_to: [ - { field_uRI: { field_uRI: 'folder:FolderClass' } }, - { field_uRI_or_constant: { constant: { value: map_folder_type(opts[:folder_type]) } } } - ] } - end - args = { - parent_folder_ids: [folder_id], - traversal: opts[:traversal], - folder_shape: { base_shape: opts[:shape] } - } - args[:restriction] = restr if restr - args - end + # Get a specific folder by id or symbol + # @param [String,Symbol,Hash] folder_id Either a FolderId(String) or a + # DistinguishedFolderId(Symbol). You can also pass a Hash in the form: + # {id: , change_key: } + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @option opts [String,nil] :act_as User to act on behalf as. This user must + # have been given delegate access to the folder or this operation will fail. + # @raise [EwsError] raised when the backend SOAP method returns an error. + def get_folder(folder_id, opts = {}) + opts = opts.clone + args = get_folder_args(folder_id, opts) + resp = ews.get_folder(args) + get_folder_parser(resp) + end - # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp - def find_folders_parser(resp) - raise EwsFolderNotFound, "Could not retrieve folders. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + # Get a specific folder by its name + # @param [String] name The folder name + # @param [Hash] opts Misc options to control request + # @option opts [String,Symbol] :parent Either a FolderId(String) or a + # DistinguishedFolderId(Symbol) . This is the parent folder. + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @option opts [String,nil] :act_as User to act on behalf as. This user must + # have been given delegate access to the folder or this operation will fail. + # @raise [EwsError] raised when the backend SOAP method returns an error. + def get_folder_by_name(name, opts = {}) + opts = opts.clone + opts[:root] = opts.delete(:parent) + folders(opts) { |obj| + obj.restriction = { + is_equal_to: [ + { field_uRI: { field_uRI: 'folder:DisplayName' } }, + { field_uRI_or_constant: { constant: { value: name } } } + ] + } + }.first + end - folders = resp.response_message[:elems][:root_folder][:elems][0][:folders][:elems] - return [] if folders.nil? + # @param [String] name The name of the new folder + # @param [Hash] opts + # @option opts [String,Symbol] :parent Either a FolderId(String) or a + # DistinguishedFolderId(Symbol) . This is the parent folder. + # @option opts [Symbol] :type the type of folder to create. must be one of + # :folder, :calendar, :contacts, :search, or :tasks + # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx + def make_folder(name, opts = {}) + parent = opts[:parent] || :msgfolderroot + resp = ews.create_folder parent_folder_id: { id: parent }, + folders: [{ folder_type(opts[:type]) => { display_name: name } }] + create_folder_parser(resp).first + end + alias mkfolder make_folder - folders.collect do |f| - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - end - end + # Get a specific folder by id or symbol + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @option opts [String,Symbol,Hash] :folder_id You can optionally specify a + # folder_id to limit the hierarchy synchronization to it. It must be a + # FolderId(String), a DistinguishedFolderId(Symbol) or you can pass a Hash + # in the form: {id: , change_key: } + # @option opts [String] :sync_state an optional Base64 encoded SyncState + # String from a previous sync call. + # @yield [Hash] yields the formatted argument Hash for last-minute + # modification before calling the backend EWS method. + # @return [Hash] A hash with the following keys + # :all_synced, whether or not additional calls are needed to get all folders + # :sync_state, the sync state to use for the next call + # and the following optional keys depending on the changes + # :create, :update, :delete + # @raise [EwsError] raised when the backend SOAP method returns an error. + def sync_folders(opts = {}) + opts = opts.clone + args = sync_folders_args(opts) + yield args if block_given? + resp = ews.sync_folder_hierarchy(args) + sync_folders_parser(resp) + end - def create_folder_parser(resp) - raise EwsError, "Could not create folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + private - folders = resp.response_message[:elems][:folders][:elems] - folders.collect do |f| - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - end - end + # Build up the arguements for #find_folders + def find_folders_args(opts) + opts[:root] = opts[:root] || :msgfolderroot + opts[:traversal] = opts[:traversal] || :shallow + opts[:shape] = opts[:shape] || :default + folder_id = { id: opts[:root] } + folder_id[:act_as] = opts[:act_as] if opts[:act_as] + if opts[:folder_type] + restr = { is_equal_to: [ + { field_uRI: { field_uRI: 'folder:FolderClass' } }, + { field_uRI_or_constant: { constant: { value: map_folder_type(opts[:folder_type]) } } } + ] } + end + args = { + parent_folder_ids: [folder_id], + traversal: opts[:traversal], + folder_shape: { base_shape: opts[:shape] } + } + args[:restriction] = restr if restr + args + end - # Build up the arguements for #get_folder - def get_folder_args(folder_id, opts) - opts[:shape] ||= :default - default_args = { - folder_shape: { base_shape: opts[:shape] } - } - default_args[:folder_ids] = if folder_id.is_a?(Hash) - [folder_id] - else - [{ id: folder_id }] - end - default_args.merge opts - end + # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp + def find_folders_parser(resp) + raise EwsFolderNotFound, + "Could not retrieve folders. #{resp.code}: #{resp.message}" unless resp.status == 'Success' - # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp - def get_folder_parser(resp) - raise EwsFolderNotFound, "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + folders = resp.response_message[:elems][:root_folder][:elems][0][:folders][:elems] + return [] if folders.nil? - f = resp.response_message[:elems][:folders][:elems][0] - ftype = f.keys.first - class_by_name(ftype).new(ews, f[ftype]) - end + folders.collect do |f| + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) + end + end - def sync_folders_args(opts) - opts[:shape] = opts[:shape] || :default - args = { folder_shape: { base_shape: opts[:shape] } } - if opts[:folder_id] - folder_id = opts[:folder_id] - args[:sync_folder_id] = if folder_id.is_a?(Hash) - folder_id - else - { id: folder_id } - end - end - args[:sync_state] = opts[:sync_state] if opts[:sync_state] - args - end + def create_folder_parser(resp) + raise EwsError, "Could not create folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' - def sync_folders_parser(resp) - rmsg = resp.response_messages[0] - raise EwsError, "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? - - rhash = {} - rhash[:all_synced] = rmsg.includes_last_folder_in_range? - rhash[:sync_state] = rmsg.sync_state - rmsg.changes.each do |c| - ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) - if ctype == :delete - rhash[ctype] << c[ctype][:elems][0][:folder_id][:attribs] - else - type = c[ctype][:elems][0].keys.first - item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) - rhash[ctype] << item + folders = resp.response_message[:elems][:folders][:elems] + folders.collect do |f| + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) + end end - end - rhash - end - # Map a passed parameter to a know folder type mapping. If no mapping - # exits simply allow the passed in type to be passed to the SOAP call. - # @param [Symbol] type a symbol in FOLDER_TYPE_MAP - def map_folder_type(type) - FOLDER_TYPE_MAP[type] || type - end + # Build up the arguements for #get_folder + def get_folder_args(folder_id, opts) + opts[:shape] ||= :default + default_args = { + folder_shape: { base_shape: opts[:shape] } + } + default_args[:folder_ids] = if folder_id.is_a?(Hash) + [folder_id] + else + [{ id: folder_id }] + end + default_args.merge opts + end - def folder_type(type) - case type - when nil, :folder - :folder - when :calendar, :contacts, :search, :tasks - "#{type}_folder".to_sym - else - raise EwsBadArgumentError, "Not a proper folder type: :#{type}" + # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp + def get_folder_parser(resp) + raise EwsFolderNotFound, + "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + f = resp.response_message[:elems][:folders][:elems][0] + ftype = f.keys.first + class_by_name(ftype).new(ews, f[ftype]) + end + + def sync_folders_args(opts) + opts[:shape] = opts[:shape] || :default + args = { folder_shape: { base_shape: opts[:shape] } } + if opts[:folder_id] + folder_id = opts[:folder_id] + args[:sync_folder_id] = if folder_id.is_a?(Hash) + folder_id + else + { id: folder_id } + end + end + args[:sync_state] = opts[:sync_state] if opts[:sync_state] + args + end + + def sync_folders_parser(resp) + rmsg = resp.response_messages[0] + raise EwsError, + "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + + rhash = {} + rhash[:all_synced] = rmsg.includes_last_folder_in_range? + rhash[:sync_state] = rmsg.sync_state + rmsg.changes.each do |c| + ctype = c.keys.first + rhash[ctype] = [] unless rhash.has_key?(ctype) + if ctype == :delete + rhash[ctype] << c[ctype][:elems][0][:folder_id][:attribs] + else + type = c[ctype][:elems][0].keys.first + item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) + rhash[ctype] << item + end + end + rhash + end + + # Map a passed parameter to a know folder type mapping. If no mapping + # exits simply allow the passed in type to be passed to the SOAP call. + # @param [Symbol] type a symbol in FOLDER_TYPE_MAP + def map_folder_type(type) + FOLDER_TYPE_MAP[type] || type + end + + def folder_type(type) + case type + when nil, :folder + :folder + when :calendar, :contacts, :search, :tasks + "#{type}_folder".to_sym + else + raise EwsBadArgumentError, "Not a proper folder type: :#{type}" + end + end end end end diff --git a/lib/ews/impersonation.rb b/lib/ews/impersonation.rb index fbca999b..4ddc9130 100644 --- a/lib/ews/impersonation.rb +++ b/lib/ews/impersonation.rb @@ -1,30 +1,33 @@ # frozen_string_literal: true -module Viewpoint::EWS - ConnectingSID = { - UPN: 'PrincipalName', - SID: 'SID', - PSMTP: 'PrimarySmtpAddress', - SMTP: 'SmtpAddress' - } - # @param connecting_type [String] should be one of the ConnectingSID variables - # ConnectingSID[:UPN] - use User Principal Name method - # ConnectingSID[:SID] - use Security Identifier method - # ConnectingSID[:PSMTP] - use primary Simple Mail Transfer Protocol method - # ConnectingSID[:SMTP] - use Simple Mail Transfer Protocol method - # you can add any other string, it will be converted into xml tag on soap request - # @param address [String] an address to include to requests for impersonation - def set_impersonation(connecting_type, address) - unless ConnectingSID.has_value? connecting_type or connecting_type.is_a? String - raise EwsBadArgumentError, "Not a proper connecting method: #{connecting_type.class}" - end +module Viewpoint + module EWS + ConnectingSID = { + UPN: 'PrincipalName', + SID: 'SID', + PSMTP: 'PrimarySmtpAddress', + SMTP: 'SmtpAddress' + } - ews.impersonation_type = connecting_type - ews.impersonation_address = address - end + # @param connecting_type [String] should be one of the ConnectingSID variables + # ConnectingSID[:UPN] - use User Principal Name method + # ConnectingSID[:SID] - use Security Identifier method + # ConnectingSID[:PSMTP] - use primary Simple Mail Transfer Protocol method + # ConnectingSID[:SMTP] - use Simple Mail Transfer Protocol method + # you can add any other string, it will be converted into xml tag on soap request + # @param address [String] an address to include to requests for impersonation + def set_impersonation(connecting_type, address) + unless ConnectingSID.has_value? connecting_type or connecting_type.is_a? String + raise EwsBadArgumentError, "Not a proper connecting method: #{connecting_type.class}" + end - def remove_impersonation - ews.impersonation_type = '' - ews.impersonation_address = '' + ews.impersonation_type = connecting_type + ews.impersonation_address = address + end + + def remove_impersonation + ews.impersonation_type = '' + ews.impersonation_address = '' + end end end diff --git a/lib/ews/item_accessors.rb b/lib/ews/item_accessors.rb index dbf51048..c4c8c7f0 100644 --- a/lib/ews/item_accessors.rb +++ b/lib/ews/item_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -14,225 +15,229 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::ItemAccessors - include Viewpoint::EWS - - # This is a class method that fetches an existing Item from the - # Exchange Store. - # @param [String] item_id The id of the item. You can also pass a Hash in the - # form: {id: , change_key: } - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @return [Item] Returns an Item or subclass of Item - # @todo Add support to fetch an item with a ChangeKey - def get_item(item_id, opts = {}) - args = get_item_args(item_id, opts.clone) - obj = OpenStruct.new(opts: args) - yield obj if block_given? - resp = ews.get_item(args) - get_item_parser(resp) - end +module Viewpoint + module EWS + module ItemAccessors + include Viewpoint::EWS + + # This is a class method that fetches an existing Item from the + # Exchange Store. + # @param [String] item_id The id of the item. You can also pass a Hash in the + # form: {id: , change_key: } + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @return [Item] Returns an Item or subclass of Item + # @todo Add support to fetch an item with a ChangeKey + def get_item(item_id, opts = {}) + args = get_item_args(item_id, opts.clone) + obj = OpenStruct.new(opts: args) + yield obj if block_given? + resp = ews.get_item(args) + get_item_parser(resp) + end - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :folder_id - # @see GenericFolder#items - def find_items(opts = {}) - args = find_items_args(opts.clone) - obj = OpenStruct.new(opts: args, restriction: {}) - yield obj if block_given? - merge_restrictions! obj - resp = ews.find_item(args) - find_items_parser resp - end + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :folder_id + # @see GenericFolder#items + def find_items(opts = {}) + args = find_items_args(opts.clone) + obj = OpenStruct.new(opts: args, restriction: {}) + yield obj if block_given? + merge_restrictions! obj + resp = ews.find_item(args) + find_items_parser resp + end - # This is a class method that fetches an existing Item from the - # Exchange Store. - # @param [String] item_id The id of the item. You can also pass a Hash in the - # form: {id: , change_key: } - # @param [Hash] opts Misc options to control request - # @option opts [Symbol] :shape :id_only/:default/:all_properties - # @return [Item] Returns an Item or subclass of Item - # @todo Add support to fetch an item with a ChangeKey - def get_items(item_ids, opts = {}) - args = get_item_args(item_ids, opts.clone) - obj = OpenStruct.new(opts: args) - yield obj if block_given? - resp = ews.get_item(args) - get_items_parser(resp) - end + # This is a class method that fetches an existing Item from the + # Exchange Store. + # @param [String] item_id The id of the item. You can also pass a Hash in the + # form: {id: , change_key: } + # @param [Hash] opts Misc options to control request + # @option opts [Symbol] :shape :id_only/:default/:all_properties + # @return [Item] Returns an Item or subclass of Item + # @todo Add support to fetch an item with a ChangeKey + def get_items(item_ids, opts = {}) + args = get_item_args(item_ids, opts.clone) + obj = OpenStruct.new(opts: args) + yield obj if block_given? + resp = ews.get_item(args) + get_items_parser(resp) + end - # Copy an array of items to the specified folder - # @param items [Array] an array of EWS Items that you want to copy - # @param folder [String,Symbol,GenericFolder] The folder to copy to. This must - # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) - # or a FolderId (String) - # @return [Array] returns a Hash for each item passed - # on success: - # {:success => true, :item_id => } - # on failure: - # {:success => false, :error_message => } - def copy_items(items, folder) - folder = folder.id if folder.is_a?(Types::GenericFolder) - item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } - copy_opts = { - to_folder_id: { id: folder }, - item_ids: item_ids - } - resp = ews.copy_item(copy_opts) - copy_move_items_parser(resp) - end + # Copy an array of items to the specified folder + # @param items [Array] an array of EWS Items that you want to copy + # @param folder [String,Symbol,GenericFolder] The folder to copy to. This must + # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) + # or a FolderId (String) + # @return [Array] returns a Hash for each item passed + # on success: + # {:success => true, :item_id => } + # on failure: + # {:success => false, :error_message => } + def copy_items(items, folder) + folder = folder.id if folder.is_a?(Types::GenericFolder) + item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } + copy_opts = { + to_folder_id: { id: folder }, + item_ids: item_ids + } + resp = ews.copy_item(copy_opts) + copy_move_items_parser(resp) + end - # Move an array of items to the specified folder - # @see #copy_items for parameter info - def move_items(items, folder) - folder = folder.id if folder.is_a?(Types::GenericFolder) - item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } - move_opts = { - to_folder_id: { id: folder }, - item_ids: item_ids - } - resp = ews.move_item(move_opts) - copy_move_items_parser(resp, :move_item_response_message) - end + # Move an array of items to the specified folder + # @see #copy_items for parameter info + def move_items(items, folder) + folder = folder.id if folder.is_a?(Types::GenericFolder) + item_ids = items.collect { |i| { item_id: { id: i.id, change_key: i.change_key } } } + move_opts = { + to_folder_id: { id: folder }, + item_ids: item_ids + } + resp = ews.move_item(move_opts) + copy_move_items_parser(resp, :move_item_response_message) + end - # Exports an entire item into base64 string - # @param item_ids [Array] array of item ids. Can also be a single id value - # return [Array] array of bulk items - def export_items(item_ids) - args = export_items_args(item_ids) + # Exports an entire item into base64 string + # @param item_ids [Array] array of item ids. Can also be a single id value + # return [Array] array of bulk items + def export_items(item_ids) + args = export_items_args(item_ids) - resp = ews.export_items(args) - export_items_parser(resp) - end + resp = ews.export_items(args) + export_items_parser(resp) + end + + private - private - - def get_item_args(item_id, opts) - opts[:shape] ||= :default - default_args = { - item_shape: { base_shape: opts[:shape] } - } - default_args[:item_ids] = case item_id - when Hash - if item_id.keys.index(:id) - [{ item_id: item_id }] - else - [item_id] - end - when Array - item_id.map do |i| - case i + def get_item_args(item_id, opts) + opts[:shape] ||= :default + default_args = { + item_shape: { base_shape: opts[:shape] } + } + default_args[:item_ids] = case item_id when Hash - i + if item_id.keys.index(:id) + [{ item_id: item_id }] + else + [item_id] + end + when Array + item_id.map do |i| + case i + when Hash + i + else + { item_id: { id: i } } + end + end else - { item_id: { id: i } } + [{ item_id: { id: item_id } }] end - end - else - [{ item_id: { id: item_id } }] - end - default_args.merge opts - end + default_args.merge opts + end - def get_item_parser(resp) - rm = resp.response_messages[0] - - if rm && rm.status == 'Success' - i = rm.items.first - itype = i.keys.first - class_by_name(itype).new(ews, i[itype]) - else - rm.respond_to?(:code) ? rm.code : 'Unknown' - rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' - raise EwsItemNotFound, "Could not retrieve item. #{rm.code}: #{rm.message_text}" - end - end + def get_item_parser(resp) + rm = resp.response_messages[0] + + if rm && rm.status == 'Success' + i = rm.items.first + itype = i.keys.first + class_by_name(itype).new(ews, i[itype]) + else + rm.respond_to?(:code) ? rm.code : 'Unknown' + rm.respond_to?(:message_text) ? rm.message_text : 'Unknown' + raise EwsItemNotFound, "Could not retrieve item. #{rm.code}: #{rm.message_text}" + end + end - def get_items_parser(resp) - items = [] + def get_items_parser(resp) + items = [] - resp.response_messages.each do |rm| - next unless rm && rm.status == 'Success' + resp.response_messages.each do |rm| + next unless rm && rm.status == 'Success' - rm.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type]) - end - end + rm.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type]) + end + end - items - end + items + end - def find_items_args(opts) - default_args = { - traversal: 'Shallow', - item_shape: { base_shape: 'Default' } - } - - default_args[:parent_folder_ids] = if opts[:folder_id].is_a?(Hash) - [opts.delete(:folder_id)] - else - [{ id: opts.delete(:folder_id) }] - end - default_args.merge(opts) - end + def find_items_args(opts) + default_args = { + traversal: 'Shallow', + item_shape: { base_shape: 'Default' } + } + + default_args[:parent_folder_ids] = if opts[:folder_id].is_a?(Hash) + [opts.delete(:folder_id)] + else + [{ id: opts.delete(:folder_id) }] + end + default_args.merge(opts) + end - def find_items_parser(resp) - rm = resp.response_messages[0] - raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.success? + def find_items_parser(resp) + rm = resp.response_messages[0] + raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.success? - items = [] - rm.root_folder.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type]) - end - items - end + items = [] + rm.root_folder.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type]) + end + items + end - def copy_move_items_parser(resp, _resp_type = :copy_item_response_message) - resp.response_messages.collect { |r| - obj = {} - if r.success? - obj[:success] = true - item = r.items.first - key = item.keys.first - obj[:item_id] = item[key][:elems][0][:item_id][:attribs][:id] - else - obj[:success] = false - obj[:error_message] = "#{r.response_code}: #{r.message_text}" + def copy_move_items_parser(resp, _resp_type = :copy_item_response_message) + resp.response_messages.collect { |r| + obj = {} + if r.success? + obj[:success] = true + item = r.items.first + key = item.keys.first + obj[:item_id] = item[key][:elems][0][:item_id][:attribs][:id] + else + obj[:success] = false + obj[:error_message] = "#{r.response_code}: #{r.message_text}" + end + obj + } end - obj - } - end - def export_items_args(item_ids) - default_args = {} - default_args[:item_ids] = [] - if item_ids.is_a?(Array) - item_ids.each do |id| - default_args[:item_ids] = default_args[:item_ids] + [{ item_id: { id: id } }] + def export_items_args(item_ids) + default_args = {} + default_args[:item_ids] = [] + if item_ids.is_a?(Array) + item_ids.each do |id| + default_args[:item_ids] = default_args[:item_ids] + [{ item_id: { id: id } }] + end + else + default_args[:item_ids] = [{ item_id: { id: item_ids } }] + end + default_args end - else - default_args[:item_ids] = [{ item_id: { id: item_ids } }] - end - default_args - end - def export_items_parser(resp) - rm = resp.response_messages - return unless rm - - items = [] - rm.each do |i| - if i.success? - type = i.type - items << class_by_name(type).new(ews, i.message[:elems]) - else - code = i.respond_to?(:code) ? i.code : 'Unknown' - text = i.respond_to?(:message_text) ? i.message_text : 'Unknown' - items << "Could not retrieve item. #{code}: #{text}" + def export_items_parser(resp) + rm = resp.response_messages + return unless rm + + items = [] + rm.each do |i| + if i.success? + type = i.type + items << class_by_name(type).new(ews, i.message[:elems]) + else + code = i.respond_to?(:code) ? i.code : 'Unknown' + text = i.respond_to?(:message_text) ? i.message_text : 'Unknown' + items << "Could not retrieve item. #{code}: #{text}" + end + end + items end end - items end end diff --git a/lib/ews/mailbox_accessors.rb b/lib/ews/mailbox_accessors.rb index 59f6d1b5..70fcc54a 100644 --- a/lib/ews/mailbox_accessors.rb +++ b/lib/ews/mailbox_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,75 +16,79 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::MailboxAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module MailboxAccessors + include Viewpoint::EWS - # Resolve contacts in the Exchange Data Store - # @param [String] ustring A string to resolve contacts to. - # @return [Array] It returns an Array of MailboxUsers. - def search_contacts(ustring) - resp = ews.resolve_names(name: ustring) + # Resolve contacts in the Exchange Data Store + # @param [String] ustring A string to resolve contacts to. + # @return [Array] It returns an Array of MailboxUsers. + def search_contacts(ustring) + resp = ews.resolve_names(name: ustring) - users = [] - if resp.status == 'Success' - mb = resp.response_message[:elems][:resolution_set][:elems][0][:resolution][:elems][0] - users << Types::MailboxUser.new(ews, mb[:mailbox][:elems]) - elsif resp.code == 'ErrorNameResolutionMultipleResults' - resp.response_message[:elems][:resolution_set][:elems].each do |u| - if u[:resolution][:elems][0][:mailbox] - users << Types::MailboxUser.new(ews, u[:resolution][:elems][0][:mailbox][:elems]) + users = [] + if resp.status == 'Success' + mb = resp.response_message[:elems][:resolution_set][:elems][0][:resolution][:elems][0] + users << Types::MailboxUser.new(ews, mb[:mailbox][:elems]) + elsif resp.code == 'ErrorNameResolutionMultipleResults' + resp.response_message[:elems][:resolution_set][:elems].each do |u| + if u[:resolution][:elems][0][:mailbox] + users << Types::MailboxUser.new(ews, u[:resolution][:elems][0][:mailbox][:elems]) + end + end + else + raise EwsError, "Find User produced an error: #{resp.code}: #{resp.message}" end + users end - else - raise EwsError, "Find User produced an error: #{resp.code}: #{resp.message}" - end - users - end - # GetUserAvailability request - # @see http://msdn.microsoft.com/en-us/library/aa563800.aspx - # @param [Array] emails A list of emails you want to retrieve free-busy info for. - # @param [Hash] opts - # @option opts [DateTime] :start_time - # @option opts [DateTime] :end_time - # @option opts [Symbol] :requested_view :merged_only/:free_busy/ - # :free_busy_merged/:detailed/:detailed_merged - # @option opts [Hash] :time_zone The TimeZone data - # Example: {:bias => 'UTC offset in minutes', - # :standard_time => {:bias => 480, :time => '02:00:00', - # :day_order => 5, :month => 10, :day_of_week => 'Sunday'}, - # :daylight_time => {same options as :standard_time}} - def get_user_availability(emails, opts) - opts = opts.clone - args = get_user_availability_args(emails, opts) - resp = ews.get_user_availability(args.merge(opts)) - get_user_availability_parser(resp) - end + # GetUserAvailability request + # @see http://msdn.microsoft.com/en-us/library/aa563800.aspx + # @param [Array] emails A list of emails you want to retrieve free-busy info for. + # @param [Hash] opts + # @option opts [DateTime] :start_time + # @option opts [DateTime] :end_time + # @option opts [Symbol] :requested_view :merged_only/:free_busy/ + # :free_busy_merged/:detailed/:detailed_merged + # @option opts [Hash] :time_zone The TimeZone data + # Example: {:bias => 'UTC offset in minutes', + # :standard_time => {:bias => 480, :time => '02:00:00', + # :day_order => 5, :month => 10, :day_of_week => 'Sunday'}, + # :daylight_time => {same options as :standard_time}} + def get_user_availability(emails, opts) + opts = opts.clone + args = get_user_availability_args(emails, opts) + resp = ews.get_user_availability(args.merge(opts)) + get_user_availability_parser(resp) + end - private + private - def get_user_availability_args(emails, opts) - unless opts.has_key?(:start_time) && opts.has_key?(:end_time) && opts.has_key?(:requested_view) - raise EwsBadArgumentError, 'You must specify a start_time, end_time and requested_view.' - end + def get_user_availability_args(emails, opts) + unless opts.has_key?(:start_time) && opts.has_key?(:end_time) && opts.has_key?(:requested_view) + raise EwsBadArgumentError, 'You must specify a start_time, end_time and requested_view.' + end - { - mailbox_data: emails.collect { |e| [{ email: { address: e } }] }.flatten, - free_busy_view_options: { - time_window: { - start_time: opts[:start_time], - end_time: opts[:end_time] - }, - requested_view: { requested_free_busy_view: opts[:requested_view] } - } - } - end + { + mailbox_data: emails.collect { |e| [{ email: { address: e } }] }.flatten, + free_busy_view_options: { + time_window: { + start_time: opts[:start_time], + end_time: opts[:end_time] + }, + requested_view: { requested_free_busy_view: opts[:requested_view] } + } + } + end - def get_user_availability_parser(resp) - unless resp.status == 'Success' - raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" - end + def get_user_availability_parser(resp) + unless resp.status == 'Success' + raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" + end - resp + resp + end + end end end diff --git a/lib/ews/meeting_accessors.rb b/lib/ews/meeting_accessors.rb index 4fc962ba..8c5133be 100644 --- a/lib/ews/meeting_accessors.rb +++ b/lib/ews/meeting_accessors.rb @@ -1,40 +1,45 @@ # frozen_string_literal: true -module Viewpoint::EWS::MeetingAccessors - include Viewpoint::EWS - - def accept_meeting(opts) - ews.create_item({ - message_disposition: 'SendOnly', - items: [{ accept_item: opts_to_item(opts) }] - }) - end - def decline_meeting(opts) - ews.create_item({ - message_disposition: 'SendOnly', - items: [{ decline_item: opts_to_item(opts) }] - }) - end +module Viewpoint + module EWS + module MeetingAccessors + include Viewpoint::EWS - def tentatively_accept_meeting(opts) - ews.create_item({ - message_disposition: 'SendOnly', - items: [{ tentatively_accept_item: opts_to_item(opts) }] - }) - end + def accept_meeting(opts) + ews.create_item({ + message_disposition: 'SendOnly', + items: [{ accept_item: opts_to_item(opts) }] + }) + end + + def decline_meeting(opts) + ews.create_item({ + message_disposition: 'SendOnly', + items: [{ decline_item: opts_to_item(opts) }] + }) + end + + def tentatively_accept_meeting(opts) + ews.create_item({ + message_disposition: 'SendOnly', + items: [{ tentatively_accept_item: opts_to_item(opts) }] + }) + end - private + private - def opts_to_item(opts) - hash = { - id: opts[:id], - change_key: opts[:change_key], - sensitivity: opts[:sensitivity] - } + def opts_to_item(opts) + hash = { + id: opts[:id], + change_key: opts[:change_key], + sensitivity: opts[:sensitivity] + } - hash[:text] = opts[:text] if opts[:text] - hash[:body_type] = (opts[:body_type] || 'Text') if opts[:text] + hash[:text] = opts[:text] if opts[:text] + hash[:body_type] = (opts[:body_type] || 'Text') if opts[:text] - hash + hash + end + end end end diff --git a/lib/ews/message_accessors.rb b/lib/ews/message_accessors.rb index a187e223..984438e6 100644 --- a/lib/ews/message_accessors.rb +++ b/lib/ews/message_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -14,76 +15,80 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::MessageAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module MessageAccessors + include Viewpoint::EWS - # Send an E-mail message - # - # @param [Hash] opts A Hash with message params - # @option opts [String] :subject The message subject - # @option opts [String] :body The message body - # @option opts [Array] :to_recipients An array of e-mail addresses to send to - # @option opts [Array] :cc_recipients An array of e-mail addresses to send to - # @option opts [Array] :bcc_recipients An array of e-mail addresses to send to - # @option opts [Array] :extended_properties An array of extended properties - # [{extended_field_uri: {epros}, value: }] or values: [, ] - # @option opts [Boolean] :draft if true it will save to the draft folder - # without sending the message. - # @option opts [String,Symbol,Hash] saved_item_folder_id Either a - # FolderId(String) or a DistinguishedFolderId(Symbol). You can also pass a - # Hash in the form: {id: , change_key: } - # @option opts [Array] :file_attachments an Array of File or Tempfile objects - # @option opts [Array] :inline_attachments an Array of Inline File or Tempfile objects - # @return [Message,Boolean] Returns true if the message is sent, false if - # nothing is returned from EWS or if draft is true it will return the - # Message object. Finally, if something goes wrong, it raises an error - # with a message stating why the e-mail could not be sent. - # @todo Finish ItemAttachments - def send_message(opts = {}, &block) - msg = Template::Message.new opts.clone - yield msg if block_given? - if msg.has_attachments? - draft = msg.draft - resp = parse_create_item(ews.create_item(msg.to_ews)) - msg.draft = true - msg.file_attachments.each do |f| - next unless f.is_a?(File) or f.is_a?(Tempfile) + # Send an E-mail message + # + # @param [Hash] opts A Hash with message params + # @option opts [String] :subject The message subject + # @option opts [String] :body The message body + # @option opts [Array] :to_recipients An array of e-mail addresses to send to + # @option opts [Array] :cc_recipients An array of e-mail addresses to send to + # @option opts [Array] :bcc_recipients An array of e-mail addresses to send to + # @option opts [Array] :extended_properties An array of extended properties + # [{extended_field_uri: {epros}, value: }] or values: [, ] + # @option opts [Boolean] :draft if true it will save to the draft folder + # without sending the message. + # @option opts [String,Symbol,Hash] saved_item_folder_id Either a + # FolderId(String) or a DistinguishedFolderId(Symbol). You can also pass a + # Hash in the form: {id: , change_key: } + # @option opts [Array] :file_attachments an Array of File or Tempfile objects + # @option opts [Array] :inline_attachments an Array of Inline File or Tempfile objects + # @return [Message,Boolean] Returns true if the message is sent, false if + # nothing is returned from EWS or if draft is true it will return the + # Message object. Finally, if something goes wrong, it raises an error + # with a message stating why the e-mail could not be sent. + # @todo Finish ItemAttachments + def send_message(opts = {}, &block) + msg = Template::Message.new opts.clone + yield msg if block_given? + if msg.has_attachments? + draft = msg.draft + resp = parse_create_item(ews.create_item(msg.to_ews)) + msg.draft = true + msg.file_attachments.each do |f| + next unless f.is_a?(File) or f.is_a?(Tempfile) - resp.add_file_attachment(f) - end - msg.inline_attachments.each do |f| - next unless f.is_a?(File) or f.is_a?(Tempfile) + resp.add_file_attachment(f) + end + msg.inline_attachments.each do |f| + next unless f.is_a?(File) or f.is_a?(Tempfile) - resp.add_inline_attachment(f) - end - if draft - resp.submit_attachments! - resp - else - resp.submit! + resp.add_inline_attachment(f) + end + if draft + resp.submit_attachments! + resp + else + resp.submit! + end + else + resp = ews.create_item(msg.to_ews) + resp.response_messages ? parse_create_item(resp) : false + end end - else - resp = ews.create_item(msg.to_ews) - resp.response_messages ? parse_create_item(resp) : false - end - end - # See #send_message for options - def draft_message(opts = {}, &block) - send_message opts.merge(draft: true), &block - end + # See #send_message for options + def draft_message(opts = {}, &block) + send_message opts.merge(draft: true), &block + end - private + private - def parse_create_item(resp) - rm = resp.response_messages[0] - raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + def parse_create_item(resp) + rm = resp.response_messages[0] + raise EwsError, "Could not send message. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' - rm.items.empty? || parse_message(rm.items.first) - end + rm.items.empty? || parse_message(rm.items.first) + end - def parse_message(msg) - mtype = msg.keys.first - class_by_name(mtype).new(ews, msg[mtype]) + def parse_message(msg) + mtype = msg.keys.first + class_by_name(mtype).new(ews, msg[mtype]) + end + end end end diff --git a/lib/ews/push_subscription_accessors.rb b/lib/ews/push_subscription_accessors.rb index a6bf408f..e84ce9ee 100644 --- a/lib/ews/push_subscription_accessors.rb +++ b/lib/ews/push_subscription_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,15 +16,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::PushSubscriptionAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module PushSubscriptionAccessors + include Viewpoint::EWS - def parse_send_notification(msg) - parser = Viewpoint::EWS::SOAP::EwsParser.new(msg) - resp = parser.parse response_class: Viewpoint::EWS::SOAP::EwsResponse - rmsg = resp.response_messages[0] - raise EwsSubscriptionError, "#{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + def parse_send_notification(msg) + parser = Viewpoint::EWS::SOAP::EwsParser.new(msg) + resp = parser.parse response_class: Viewpoint::EWS::SOAP::EwsResponse + rmsg = resp.response_messages[0] + raise EwsSubscriptionError, "#{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? - rmsg + rmsg + end + end end end diff --git a/lib/ews/room_accessors.rb b/lib/ews/room_accessors.rb index cd5adfdf..8283e07a 100644 --- a/lib/ews/room_accessors.rb +++ b/lib/ews/room_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock @@ -15,30 +16,34 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::RoomAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module RoomAccessors + include Viewpoint::EWS - # Gets the rooms that are available within the specified room distribution list - # @see http://msdn.microsoft.com/en-us/library/dd899415.aspx - # @param [String] roomDistributionList - def get_rooms(roomDistributionList) - resp = ews.get_rooms(roomDistributionList) - get_rooms_parser(resp) - end + # Gets the rooms that are available within the specified room distribution list + # @see http://msdn.microsoft.com/en-us/library/dd899415.aspx + # @param [String] roomDistributionList + def get_rooms(roomDistributionList) + resp = ews.get_rooms(roomDistributionList) + get_rooms_parser(resp) + end - def room_name(room) - room[:room][:elems][:id][:elems][0][:name][:text] - end + def room_name(room) + room[:room][:elems][:id][:elems][0][:name][:text] + end - def room_email(room) - room[:room][:elems][:id][:elems][1][:email_address][:text] - end + def room_email(room) + room[:room][:elems][:id][:elems][1][:email_address][:text] + end - private + private - def get_rooms_parser(resp) - raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}" unless resp.success? + def get_rooms_parser(resp) + raise EwsError, "GetRooms produced an error: #{resp.code}: #{resp.message}" unless resp.success? - resp + resp + end + end end end diff --git a/lib/ews/roomlist_accessors.rb b/lib/ews/roomlist_accessors.rb index 98dc2acf..4f86fe90 100644 --- a/lib/ews/roomlist_accessors.rb +++ b/lib/ews/roomlist_accessors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock @@ -15,29 +16,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::RoomlistAccessors - include Viewpoint::EWS +module Viewpoint + module EWS + module RoomlistAccessors + include Viewpoint::EWS - # Gets the room lists that are available within the Exchange organization. - # @see http://msdn.microsoft.com/en-us/library/dd899416.aspx - def get_room_lists - resp = ews.get_room_lists - get_room_lists_parser(resp) - end + # Gets the room lists that are available within the Exchange organization. + # @see http://msdn.microsoft.com/en-us/library/dd899416.aspx + def get_room_lists + resp = ews.get_room_lists + get_room_lists_parser(resp) + end - def roomlist_name(roomlist) - roomlist[:address][:elems][:name][:text] - end + def roomlist_name(roomlist) + roomlist[:address][:elems][:name][:text] + end - def roomlist_email(roomlist) - roomlist[:address][:elems][:email_address][:text] - end + def roomlist_email(roomlist) + roomlist[:address][:elems][:email_address][:text] + end - private + private - def get_room_lists_parser(resp) - raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}" unless resp.success? + def get_room_lists_parser(resp) + raise EwsError, "GetRoomLists produced an error: #{resp.code}: #{resp.message}" unless resp.success? - resp + resp + end + end end end diff --git a/lib/ews/soap.rb b/lib/ews/soap.rb index 4236ffa9..a0912998 100644 --- a/lib/ews/soap.rb +++ b/lib/ews/soap.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index 6a0f023a..1d12972a 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -14,1355 +15,1359 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # This class includes the element builders. The idea is that each element should - # know how to build themselves so each parent element can delegate creation of - # subelements to a method of the same name with a '!' after it. - class EwsBuilder - include Viewpoint::EWS - include Viewpoint::StringUtils - - attr_reader :nbuild - - def initialize - @nbuild = Nokogiri::XML::Builder.new - end +module Viewpoint + module EWS + module SOAP + # This class includes the element builders. The idea is that each element should + # know how to build themselves so each parent element can delegate creation of + # subelements to a method of the same name with a '!' after it. + class EwsBuilder + include Viewpoint::EWS + include Viewpoint::StringUtils + + attr_reader :nbuild + + def initialize + @nbuild = Nokogiri::XML::Builder.new + end - # Build the SOAP envelope and yield this object so subelements can be built. Once - # you have the EwsBuilder object you can use the nbuild object like shown in the - # example for the Header section. The nbuild object is the underlying - # Nokogiri::XML::Builder object. - # @param [Hash] opts - # @option opts [String] :server_version The version string that should get - # set in the Header. See ExchangeWebService#initialize - # @option opts [Hash] :time_zone_context TimeZoneDefinition. Format: !{id: time_zone_identifier} - # @example - # xb = EwsBuilder.new - # xb.build! do |part, b| - # if(part == :header) - # b.nbuild.MyVar('blablabla') - # else - # b.folder_shape!({:base_shape => 'Default'}) - # end - # end - def build!(opts = {}, &block) - @nbuild.Envelope(NAMESPACES) do |node| - node.parent.namespace = parent_namespace(node) - node.Header do - set_version_header! opts[:server_version] - set_impersonation! opts[:impersonation_type], opts[:impersonation_mail] - set_time_zone_context_header! opts[:time_zone_context] - yield(:header, self) if block_given? - end - node.Body { - yield(:body, self) if block_given? - } - end - @nbuild.doc - end + # Build the SOAP envelope and yield this object so subelements can be built. Once + # you have the EwsBuilder object you can use the nbuild object like shown in the + # example for the Header section. The nbuild object is the underlying + # Nokogiri::XML::Builder object. + # @param [Hash] opts + # @option opts [String] :server_version The version string that should get + # set in the Header. See ExchangeWebService#initialize + # @option opts [Hash] :time_zone_context TimeZoneDefinition. Format: !{id: time_zone_identifier} + # @example + # xb = EwsBuilder.new + # xb.build! do |part, b| + # if(part == :header) + # b.nbuild.MyVar('blablabla') + # else + # b.folder_shape!({:base_shape => 'Default'}) + # end + # end + def build!(opts = {}, &block) + @nbuild.Envelope(NAMESPACES) do |node| + node.parent.namespace = parent_namespace(node) + node.Header do + set_version_header! opts[:server_version] + set_impersonation! opts[:impersonation_type], opts[:impersonation_mail] + set_time_zone_context_header! opts[:time_zone_context] + yield(:header, self) if block_given? + end + node.Body { + yield(:body, self) if block_given? + } + end + @nbuild.doc + end - # Build XML from a passed in Hash or Array in a specified format. - # @param [Array,Hash] elems The elements to add to the Builder. They must - # be specified like so: - # - # !{:top => - # { :xmlns => 'http://stonesthrow/soap', - # :sub_elements => [ - # {:elem1 => {:text => 'inside'}}, - # {:elem2 => {:text => 'inside2'}} - # ], - # :id => '3232', :tx_dd => 23, :asdf => 'turkey' - # } - # } - # or - # [ {:first => {:text => 'hello'}}, - # {:second => {:text => 'world'}} - # ] - # - # NOTE: there are specialized keys for text (:text), child elements - # (:sub_elements) and namespaces (:xmlns). - def build_xml!(elems) - case elems.class.name - when 'Hash' - keys = elems.keys - vals = elems.values - raise "invalid input: #{elems}" if keys.length > 1 && !vals.is_a?(Hash) - - vals = vals.first.clone - se = vals.delete(:sub_elements) - txt = vals.delete(:text) - xmlns_attribute = vals.delete(:xmlns_attribute) - - node = @nbuild.send(camel_case(keys.first), txt, vals) { |_x| - build_xml!(se) if se - } - - # Set node level namespace - node.xmlns = NAMESPACES["xmlns:#{xmlns_attribute}"] if xmlns_attribute - when 'Array' - elems.each do |e| - build_xml!(e) - end - else - raise "Unsupported type: #{elems.class.name}" - end - end + # Build XML from a passed in Hash or Array in a specified format. + # @param [Array,Hash] elems The elements to add to the Builder. They must + # be specified like so: + # + # !{:top => + # { :xmlns => 'http://stonesthrow/soap', + # :sub_elements => [ + # {:elem1 => {:text => 'inside'}}, + # {:elem2 => {:text => 'inside2'}} + # ], + # :id => '3232', :tx_dd => 23, :asdf => 'turkey' + # } + # } + # or + # [ {:first => {:text => 'hello'}}, + # {:second => {:text => 'world'}} + # ] + # + # NOTE: there are specialized keys for text (:text), child elements + # (:sub_elements) and namespaces (:xmlns). + def build_xml!(elems) + case elems.class.name + when 'Hash' + keys = elems.keys + vals = elems.values + raise "invalid input: #{elems}" if keys.length > 1 && !vals.is_a?(Hash) + + vals = vals.first.clone + se = vals.delete(:sub_elements) + txt = vals.delete(:text) + xmlns_attribute = vals.delete(:xmlns_attribute) + + node = @nbuild.send(camel_case(keys.first), txt, vals) { |_x| + build_xml!(se) if se + } + + # Set node level namespace + node.xmlns = NAMESPACES["xmlns:#{xmlns_attribute}"] if xmlns_attribute + when 'Array' + elems.each do |e| + build_xml!(e) + end + else + raise "Unsupported type: #{elems.class.name}" + end + end - # Build the FolderShape element - # @see http://msdn.microsoft.com/en-us/library/aa494311.aspx - # @param [Hash] folder_shape The folder shape structure to build from - # @todo need fully support all options - def folder_shape!(folder_shape) - @nbuild.FolderShape { - @nbuild.parent.default_namespace = @default_ns - base_shape!(folder_shape[:base_shape]) - additional_properties!(folder_shape[:additional_properties]) if folder_shape[:additional_properties] - } - end + # Build the FolderShape element + # @see http://msdn.microsoft.com/en-us/library/aa494311.aspx + # @param [Hash] folder_shape The folder shape structure to build from + # @todo need fully support all options + def folder_shape!(folder_shape) + @nbuild.FolderShape { + @nbuild.parent.default_namespace = @default_ns + base_shape!(folder_shape[:base_shape]) + additional_properties!(folder_shape[:additional_properties]) if folder_shape[:additional_properties] + } + end - # Build the ItemShape element - # @see http://msdn.microsoft.com/en-us/library/aa565261.aspx - # @param [Hash] item_shape The item shape structure to build from - # @todo need fully support all options - def item_shape!(item_shape) - @nbuild[NS_EWS_MESSAGES].ItemShape { - @nbuild.parent.default_namespace = @default_ns - base_shape!(item_shape[:base_shape]) - mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content) - body_type!(item_shape[:body_type]) if item_shape[:body_type] - additional_properties!(item_shape[:additional_properties]) if item_shape[:additional_properties] - } - end + # Build the ItemShape element + # @see http://msdn.microsoft.com/en-us/library/aa565261.aspx + # @param [Hash] item_shape The item shape structure to build from + # @todo need fully support all options + def item_shape!(item_shape) + @nbuild[NS_EWS_MESSAGES].ItemShape { + @nbuild.parent.default_namespace = @default_ns + base_shape!(item_shape[:base_shape]) + mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content) + body_type!(item_shape[:body_type]) if item_shape[:body_type] + additional_properties!(item_shape[:additional_properties]) if item_shape[:additional_properties] + } + end - # Build the IndexedPageItemView element - # @see http://msdn.microsoft.com/en-us/library/exchange/aa563549(v=exchg.150).aspx - # @todo needs peer check - def indexed_page_item_view!(indexed_page_item_view) - attribs = {} - indexed_page_item_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end - @nbuild[NS_EWS_MESSAGES].IndexedPageItemView(attribs) - end + # Build the IndexedPageItemView element + # @see http://msdn.microsoft.com/en-us/library/exchange/aa563549(v=exchg.150).aspx + # @todo needs peer check + def indexed_page_item_view!(indexed_page_item_view) + attribs = {} + indexed_page_item_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end + @nbuild[NS_EWS_MESSAGES].IndexedPageItemView(attribs) + end - # Build the BaseShape element - # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx - def base_shape!(base_shape) - @nbuild[NS_EWS_TYPES].BaseShape(camel_case(base_shape)) - end + # Build the BaseShape element + # @see http://msdn.microsoft.com/en-us/library/aa580545.aspx + def base_shape!(base_shape) + @nbuild[NS_EWS_TYPES].BaseShape(camel_case(base_shape)) + end - def mime_content!(include_mime_content) - @nbuild[NS_EWS_TYPES].IncludeMimeContent(include_mime_content.to_s.downcase) - end + def mime_content!(include_mime_content) + @nbuild[NS_EWS_TYPES].IncludeMimeContent(include_mime_content.to_s.downcase) + end - def body_type!(body_type) - body_type = body_type.to_s - body_type = if body_type =~ /html/i - body_type.upcase - else - body_type.downcase.capitalize - end - nbuild[NS_EWS_TYPES].BodyType(body_type) - end + def body_type!(body_type) + body_type = body_type.to_s + body_type = if body_type =~ /html/i + body_type.upcase + else + body_type.downcase.capitalize + end + nbuild[NS_EWS_TYPES].BodyType(body_type) + end - # Build the ParentFolderIds element - # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx - def parent_folder_ids!(pfids) - @nbuild[NS_EWS_MESSAGES].ParentFolderIds { - pfids.each do |pfid| - dispatch_folder_id!(pfid) + # Build the ParentFolderIds element + # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx + def parent_folder_ids!(pfids) + @nbuild[NS_EWS_MESSAGES].ParentFolderIds { + pfids.each do |pfid| + dispatch_folder_id!(pfid) + end + } end - } - end - # Build the ParentFolderId element - # @see http://msdn.microsoft.com/en-us/library/aa563268.aspx - def parent_folder_id!(pfid) - @nbuild.ParentFolderId { - dispatch_folder_id!(pfid) - } - end + # Build the ParentFolderId element + # @see http://msdn.microsoft.com/en-us/library/aa563268.aspx + def parent_folder_id!(pfid) + @nbuild.ParentFolderId { + dispatch_folder_id!(pfid) + } + end - # Build the FolderIds element - # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx - def folder_ids!(fids, act_as = nil) - ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES - @nbuild[ns].FolderIds { - fids.each do |fid| - fid[:act_as] = act_as unless act_as.nil? - dispatch_folder_id!(fid) + # Build the FolderIds element + # @see http://msdn.microsoft.com/en-us/library/aa580509.aspx + def folder_ids!(fids, act_as = nil) + ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES + @nbuild[ns].FolderIds { + fids.each do |fid| + fid[:act_as] = act_as unless act_as.nil? + dispatch_folder_id!(fid) + end + } end - } - end - # Build the SyncFolderId element - # @see http://msdn.microsoft.com/en-us/library/aa580296.aspx - def sync_folder_id!(fid) - @nbuild.SyncFolderId { - dispatch_folder_id!(fid) - } - end + # Build the SyncFolderId element + # @see http://msdn.microsoft.com/en-us/library/aa580296.aspx + def sync_folder_id!(fid) + @nbuild.SyncFolderId { + dispatch_folder_id!(fid) + } + end - # Build the DistinguishedFolderId element - # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx - # @todo add support for the Mailbox child object - def distinguished_folder_id!(dfid, change_key = nil, act_as = nil) - attribs = { 'Id' => dfid.to_s } - attribs['ChangeKey'] = change_key if change_key - @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) { - mailbox!({ email_address: act_as }) unless act_as.nil? - } - end + # Build the DistinguishedFolderId element + # @see http://msdn.microsoft.com/en-us/library/aa580808.aspx + # @todo add support for the Mailbox child object + def distinguished_folder_id!(dfid, change_key = nil, act_as = nil) + attribs = { 'Id' => dfid.to_s } + attribs['ChangeKey'] = change_key if change_key + @nbuild[NS_EWS_TYPES].DistinguishedFolderId(attribs) { + mailbox!({ email_address: act_as }) unless act_as.nil? + } + end - # Build the FolderId element - # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx - def folder_id!(fid, change_key = nil) - attribs = { 'Id' => fid } - attribs['ChangeKey'] = change_key if change_key - @nbuild[NS_EWS_TYPES].FolderId(attribs) - end + # Build the FolderId element + # @see http://msdn.microsoft.com/en-us/library/aa579461.aspx + def folder_id!(fid, change_key = nil) + attribs = { 'Id' => fid } + attribs['ChangeKey'] = change_key if change_key + @nbuild[NS_EWS_TYPES].FolderId(attribs) + end - # @see http://msdn.microsoft.com/en-us/library/aa563525(v=EXCHG.140).aspx - def item_ids!(item_ids) - @nbuild.ItemIds { - item_ids.each do |iid| - dispatch_item_id!(iid) + # @see http://msdn.microsoft.com/en-us/library/aa563525(v=EXCHG.140).aspx + def item_ids!(item_ids) + @nbuild.ItemIds { + item_ids.each do |iid| + dispatch_item_id!(iid) + end + } end - } - end - def parent_item_id!(id) - nbuild.ParentItemId { |x| - x.parent['Id'] = id[:id] - x.parent['ChangeKey'] = id[:change_key] if id[:change_key] - } - end + def parent_item_id!(id) + nbuild.ParentItemId { |x| + x.parent['Id'] = id[:id] + x.parent['ChangeKey'] = id[:change_key] if id[:change_key] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx - def item_id!(id) - nbuild[NS_EWS_TYPES].ItemId { |x| - x.parent['Id'] = id[:id] - x.parent['ChangeKey'] = id[:change_key] if id[:change_key] - } - end + # @see http://msdn.microsoft.com/en-us/library/aa580234(v=EXCHG.140).aspx + def item_id!(id) + nbuild[NS_EWS_TYPES].ItemId { |x| + x.parent['Id'] = id[:id] + x.parent['ChangeKey'] = id[:change_key] if id[:change_key] + } + end - # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx - def export_item_ids!(item_ids) - ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES - @nbuild[ns].ExportItems { - @nbuild.ItemIds { - item_ids.each do |iid| - dispatch_item_id!(iid) - end - } - } - end + # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx + def export_item_ids!(item_ids) + ns = @nbuild.parent.name.match(/subscription/i) ? NS_EWS_TYPES : NS_EWS_MESSAGES + @nbuild[ns].ExportItems { + @nbuild.ItemIds { + item_ids.each do |iid| + dispatch_item_id!(iid) + end + } + } + end - # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx - def occurrence_item_id!(id) - @nbuild[NS_EWS_TYPES].OccurrenceItemId { |x| - x.parent['RecurringMasterId'] = id[:recurring_master_id] - x.parent['ChangeKey'] = id[:change_key] if id[:change_key] - x.parent['InstanceIndex'] = id[:instance_index] - } - end + # @see http://msdn.microsoft.com/en-us/library/aa580744(v=EXCHG.140).aspx + def occurrence_item_id!(id) + @nbuild[NS_EWS_TYPES].OccurrenceItemId { |x| + x.parent['RecurringMasterId'] = id[:recurring_master_id] + x.parent['ChangeKey'] = id[:change_key] if id[:change_key] + x.parent['InstanceIndex'] = id[:instance_index] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx - def recurring_master_item_id!(id) - @nbuild[NS_EWS_TYPES].RecurringMasterItemId { |x| - x.parent['OccurrenceId'] = id[:occurrence_id] - x.parent['ChangeKey'] = id[:change_key] if id[:change_key] - } - end + # @see http://msdn.microsoft.com/en-us/library/aa581019(v=EXCHG.140).aspx + def recurring_master_item_id!(id) + @nbuild[NS_EWS_TYPES].RecurringMasterItemId { |x| + x.parent['OccurrenceId'] = id[:occurrence_id] + x.parent['ChangeKey'] = id[:change_key] if id[:change_key] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa565020(v=EXCHG.140).aspx - def to_folder_id!(to_fid) - @nbuild[NS_EWS_MESSAGES].ToFolderId { - dispatch_folder_id!(to_fid) - } - end + # @see http://msdn.microsoft.com/en-us/library/aa565020(v=EXCHG.140).aspx + def to_folder_id!(to_fid) + @nbuild[NS_EWS_MESSAGES].ToFolderId { + dispatch_folder_id!(to_fid) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx - def folders!(folders) - @nbuild.Folders { |_x| - folders.each do |fold| - fold.each_pair do |ftype, vars| # convenience, should only be one pair - ftype = "#{ftype}!".to_sym - if respond_to? ftype - send ftype, vars - else - raise Viewpoint::EWS::EwsNotImplemented, - "#{ftype} not implemented as a builder." + # @see http://msdn.microsoft.com/en-us/library/aa564009.aspx + def folders!(folders) + @nbuild.Folders { |_x| + folders.each do |fold| + fold.each_pair do |ftype, vars| # convenience, should only be one pair + ftype = "#{ftype}!".to_sym + if respond_to? ftype + send ftype, vars + else + raise Viewpoint::EWS::EwsNotImplemented, + "#{ftype} not implemented as a builder." + end + end end - end + } end - } - end - def folder!(folder, type = :Folder) - nbuild[NS_EWS_TYPES].send(type) { |_x| - folder.each_pair do |e, v| - ftype = "#{e}!".to_sym - if e == :folder_id - dispatch_folder_id!(v) - elsif respond_to?(ftype) - send ftype, v - else - raise Viewpoint::EWS::EwsNotImplemented, - "#{ftype} not implemented as a builder." - end + def folder!(folder, type = :Folder) + nbuild[NS_EWS_TYPES].send(type) { |_x| + folder.each_pair do |e, v| + ftype = "#{e}!".to_sym + if e == :folder_id + dispatch_folder_id!(v) + elsif respond_to?(ftype) + send ftype, v + else + raise Viewpoint::EWS::EwsNotImplemented, + "#{ftype} not implemented as a builder." + end + end + } end - } - end - def calendar_folder!(folder) - folder! folder, :CalendarFolder - end + def calendar_folder!(folder) + folder! folder, :CalendarFolder + end - def contacts_folder!(folder) - folder! folder, :ContactsFolder - end + def contacts_folder!(folder) + folder! folder, :ContactsFolder + end - def search_folder!(folder) - folder! folder, :SearchFolder - end + def search_folder!(folder) + folder! folder, :SearchFolder + end - def tasks_folder!(folder) - folder! folder, :TasksFolder - end + def tasks_folder!(folder) + folder! folder, :TasksFolder + end - def display_name!(name) - nbuild[NS_EWS_TYPES].DisplayName(name) - end + def display_name!(name) + nbuild[NS_EWS_TYPES].DisplayName(name) + end - # Build the AdditionalProperties element - # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx - def additional_properties!(addprops) - @nbuild[NS_EWS_TYPES].AdditionalProperties { - addprops.each_pair { |k, v| - dispatch_field_uri!({ k => v }, NS_EWS_TYPES) - } - } - end + # Build the AdditionalProperties element + # @see http://msdn.microsoft.com/en-us/library/aa563810.aspx + def additional_properties!(addprops) + @nbuild[NS_EWS_TYPES].AdditionalProperties { + addprops.each_pair { |k, v| + dispatch_field_uri!({ k => v }, NS_EWS_TYPES) + } + } + end - # Build the Mailbox element. - # This element is commonly used for delegation. Typically passing an - # email_address is sufficient - # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx - # @param [Hash] mailbox A well-formated hash - def mailbox!(mbox) - nbuild[NS_EWS_TYPES].Mailbox { - name!(mbox[:name]) if mbox[:name] - email_address!(mbox[:email_address]) if mbox[:email_address] - address!(mbox[:address]) if mbox[:address] # for Availability query - routing_type!(mbox[:routing_type]) if mbox[:routing_type] - mailbox_type!(mbox[:mailbox_type]) if mbox[:mailbox_type] - item_id!(mbox[:item_id]) if mbox[:item_id] - } - end + # Build the Mailbox element. + # This element is commonly used for delegation. Typically passing an + # email_address is sufficient + # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx + # @param [Hash] mailbox A well-formated hash + def mailbox!(mbox) + nbuild[NS_EWS_TYPES].Mailbox { + name!(mbox[:name]) if mbox[:name] + email_address!(mbox[:email_address]) if mbox[:email_address] + address!(mbox[:address]) if mbox[:address] # for Availability query + routing_type!(mbox[:routing_type]) if mbox[:routing_type] + mailbox_type!(mbox[:mailbox_type]) if mbox[:mailbox_type] + item_id!(mbox[:item_id]) if mbox[:item_id] + } + end - def name!(name) - nbuild[NS_EWS_TYPES].Name(name) - end + def name!(name) + nbuild[NS_EWS_TYPES].Name(name) + end - def email_address!(email) - nbuild[NS_EWS_TYPES].EmailAddress(email) - end + def email_address!(email) + nbuild[NS_EWS_TYPES].EmailAddress(email) + end - def address!(email) - nbuild[NS_EWS_TYPES].Address(email) - end + def address!(email) + nbuild[NS_EWS_TYPES].Address(email) + end - # This is stupid. The only valid value is "SMTP" - def routing_type!(type) - nbuild[NS_EWS_TYPES].RoutingType(type) - end + # This is stupid. The only valid value is "SMTP" + def routing_type!(type) + nbuild[NS_EWS_TYPES].RoutingType(type) + end - def mailbox_type!(type) - Standard - nbuild[NS_EWS_TYPES].MailboxType(type) - end + def mailbox_type!(type) + Standard + nbuild[NS_EWS_TYPES].MailboxType(type) + end - def user_oof_settings!(opts) - nbuild[NS_EWS_TYPES].UserOofSettings { - nbuild.OofState(camel_case(opts[:oof_state])) - nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience] - duration!(opts[:duration]) if opts[:duration] - if opts[:external_reply] - nbuild.InternalReply { - nbuild.Message(opts[:internal_reply]) + def user_oof_settings!(opts) + nbuild[NS_EWS_TYPES].UserOofSettings { + nbuild.OofState(camel_case(opts[:oof_state])) + nbuild.ExternalAudience(camel_case(opts[:external_audience])) if opts[:external_audience] + duration!(opts[:duration]) if opts[:duration] + if opts[:external_reply] + nbuild.InternalReply { + nbuild.Message(opts[:internal_reply]) + } + end + if opts[:external_reply] + nbuild.ExternalReply { + nbuild.Message(opts[:external_reply]) + } + end } end - if opts[:external_reply] - nbuild.ExternalReply { - nbuild.Message(opts[:external_reply]) + + def duration!(opts) + nbuild.Duration { + nbuild.StartTime(format_time(opts[:start_time])) + nbuild.EndTime(format_time(opts[:end_time])) } end - } - end - - def duration!(opts) - nbuild.Duration { - nbuild.StartTime(format_time(opts[:start_time])) - nbuild.EndTime(format_time(opts[:end_time])) - } - end - def mailbox_data!(md) - nbuild[NS_EWS_TYPES].MailboxData { - nbuild[NS_EWS_TYPES].Email do - mbox = md[:email] - name!(mbox[:name]) if mbox[:name] - address!(mbox[:address]) if mbox[:address] # for Availability query - routing_type!(mbox[:routing_type]) if mbox[:routing_type] + def mailbox_data!(md) + nbuild[NS_EWS_TYPES].MailboxData { + nbuild[NS_EWS_TYPES].Email do + mbox = md[:email] + name!(mbox[:name]) if mbox[:name] + address!(mbox[:address]) if mbox[:address] # for Availability query + routing_type!(mbox[:routing_type]) if mbox[:routing_type] + end + nbuild[NS_EWS_TYPES].AttendeeType 'Required' + } end - nbuild[NS_EWS_TYPES].AttendeeType 'Required' - } - end - def free_busy_view_options!(opts) - nbuild[NS_EWS_TYPES].FreeBusyViewOptions { - nbuild[NS_EWS_TYPES].TimeWindow do - nbuild[NS_EWS_TYPES].StartTime(format_time(opts[:time_window][:start_time])) - nbuild[NS_EWS_TYPES].EndTime(format_time(opts[:time_window][:end_time])) + def free_busy_view_options!(opts) + nbuild[NS_EWS_TYPES].FreeBusyViewOptions { + nbuild[NS_EWS_TYPES].TimeWindow do + nbuild[NS_EWS_TYPES].StartTime(format_time(opts[:time_window][:start_time])) + nbuild[NS_EWS_TYPES].EndTime(format_time(opts[:time_window][:end_time])) + end + nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view])) + } end - nbuild[NS_EWS_TYPES].RequestedView(camel_case(opts[:requested_view][:requested_free_busy_view])) - } - end - def suggestions_view_options!(opts); end - - def time_zone!(zone) - zone ||= {} - zone = { - bias: zone[:bias] || 480, - standard_time: { - bias: 0, - time: '02:00:00', - day_order: 5, - month: 10, - day_of_week: 'Sunday' - }.merge(zone[:standard_time] || {}), - daylight_time: { - bias: -60, - time: '02:00:00', - day_order: 1, - month: 4, - day_of_week: 'Sunday' - }.merge(zone[:daylight_time] || {}) - } - - nbuild[NS_EWS_TYPES].TimeZone { - nbuild[NS_EWS_TYPES].Bias(zone[:bias]) - nbuild[NS_EWS_TYPES].StandardTime do - nbuild[NS_EWS_TYPES].Bias(zone[:standard_time][:bias]) - nbuild[NS_EWS_TYPES].Time(zone[:standard_time][:time]) - nbuild[NS_EWS_TYPES].DayOrder(zone[:standard_time][:day_order]) - nbuild[NS_EWS_TYPES].Month(zone[:standard_time][:month]) - nbuild[NS_EWS_TYPES].DayOfWeek(zone[:standard_time][:day_of_week]) - end - nbuild[NS_EWS_TYPES].DaylightTime { - nbuild[NS_EWS_TYPES].Bias(zone[:daylight_time][:bias]) - nbuild[NS_EWS_TYPES].Time(zone[:daylight_time][:time]) - nbuild[NS_EWS_TYPES].DayOrder(zone[:daylight_time][:day_order]) - nbuild[NS_EWS_TYPES].Month(zone[:daylight_time][:month]) - nbuild[NS_EWS_TYPES].DayOfWeek(zone[:daylight_time][:day_of_week]) - } - } - end + def suggestions_view_options!(opts); end + + def time_zone!(zone) + zone ||= {} + zone = { + bias: zone[:bias] || 480, + standard_time: { + bias: 0, + time: '02:00:00', + day_order: 5, + month: 10, + day_of_week: 'Sunday' + }.merge(zone[:standard_time] || {}), + daylight_time: { + bias: -60, + time: '02:00:00', + day_order: 1, + month: 4, + day_of_week: 'Sunday' + }.merge(zone[:daylight_time] || {}) + } + + nbuild[NS_EWS_TYPES].TimeZone { + nbuild[NS_EWS_TYPES].Bias(zone[:bias]) + nbuild[NS_EWS_TYPES].StandardTime do + nbuild[NS_EWS_TYPES].Bias(zone[:standard_time][:bias]) + nbuild[NS_EWS_TYPES].Time(zone[:standard_time][:time]) + nbuild[NS_EWS_TYPES].DayOrder(zone[:standard_time][:day_order]) + nbuild[NS_EWS_TYPES].Month(zone[:standard_time][:month]) + nbuild[NS_EWS_TYPES].DayOfWeek(zone[:standard_time][:day_of_week]) + end + nbuild[NS_EWS_TYPES].DaylightTime { + nbuild[NS_EWS_TYPES].Bias(zone[:daylight_time][:bias]) + nbuild[NS_EWS_TYPES].Time(zone[:daylight_time][:time]) + nbuild[NS_EWS_TYPES].DayOrder(zone[:daylight_time][:day_order]) + nbuild[NS_EWS_TYPES].Month(zone[:daylight_time][:month]) + nbuild[NS_EWS_TYPES].DayOfWeek(zone[:daylight_time][:day_of_week]) + } + } + end - # Request all known time_zones from server - def get_server_time_zones!(get_time_zone_options) - nbuild[NS_EWS_MESSAGES].GetServerTimeZones('ReturnFullTimeZoneData' => get_time_zone_options[:full]) do - if get_time_zone_options[:ids] && get_time_zone_options[:ids].any? - nbuild[NS_EWS_MESSAGES].Ids do - get_time_zone_options[:ids].each do |id| - nbuild[NS_EWS_TYPES].Id id + # Request all known time_zones from server + def get_server_time_zones!(get_time_zone_options) + nbuild[NS_EWS_MESSAGES].GetServerTimeZones('ReturnFullTimeZoneData' => get_time_zone_options[:full]) do + if get_time_zone_options[:ids] && get_time_zone_options[:ids].any? + nbuild[NS_EWS_MESSAGES].Ids do + get_time_zone_options[:ids].each do |id| + nbuild[NS_EWS_TYPES].Id id + end + end end end end - end - end - # Specifies an optional time zone for the start time - # @param [Hash] attributes - # @option attributes :id [String] ID of the Microsoft well known time zone - # @option attributes :name [String] Optional name of the time zone - # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone - # @see http://msdn.microsoft.com/en-us/library/exchange/dd899524.aspx - def start_time_zone!(zone) - attributes = {} - attributes['Id'] = zone[:id] if zone[:id] - attributes['Name'] = zone[:name] if zone[:name] - nbuild[NS_EWS_TYPES].StartTimeZone(attributes) - end + # Specifies an optional time zone for the start time + # @param [Hash] attributes + # @option attributes :id [String] ID of the Microsoft well known time zone + # @option attributes :name [String] Optional name of the time zone + # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone + # @see http://msdn.microsoft.com/en-us/library/exchange/dd899524.aspx + def start_time_zone!(zone) + attributes = {} + attributes['Id'] = zone[:id] if zone[:id] + attributes['Name'] = zone[:name] if zone[:name] + nbuild[NS_EWS_TYPES].StartTimeZone(attributes) + end - # Specifies an optional time zone for the end time - # @param [Hash] attributes - # @option attributes :id [String] ID of the Microsoft well known time zone - # @option attributes :name [String] Optional name of the time zone - # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone - # @see http://msdn.microsoft.com/en-us/library/exchange/dd899434.aspx - def end_time_zone!(zone) - attributes = {} - attributes['Id'] = zone[:id] if zone[:id] - attributes['Name'] = zone[:name] if zone[:name] - nbuild[NS_EWS_TYPES].EndTimeZone(attributes) - end + # Specifies an optional time zone for the end time + # @param [Hash] attributes + # @option attributes :id [String] ID of the Microsoft well known time zone + # @option attributes :name [String] Optional name of the time zone + # @todo Implement sub elements Periods, TransitionsGroups and Transitions to override zone + # @see http://msdn.microsoft.com/en-us/library/exchange/dd899434.aspx + def end_time_zone!(zone) + attributes = {} + attributes['Id'] = zone[:id] if zone[:id] + attributes['Name'] = zone[:name] if zone[:name] + nbuild[NS_EWS_TYPES].EndTimeZone(attributes) + end - # Specify a time zone - # @todo Implement subelements Periods, TransitionsGroups and Transitions to override zone - # @see http://msdn.microsoft.com/en-us/library/exchange/dd899488.aspx - def time_zone_definition!(zone) - attributes = { 'Id' => zone[:id] } - attributes['Name'] = zone[:name] if zone[:name] - nbuild[NS_EWS_TYPES].TimeZoneDefinition(attributes) - end + # Specify a time zone + # @todo Implement subelements Periods, TransitionsGroups and Transitions to override zone + # @see http://msdn.microsoft.com/en-us/library/exchange/dd899488.aspx + def time_zone_definition!(zone) + attributes = { 'Id' => zone[:id] } + attributes['Name'] = zone[:name] if zone[:name] + nbuild[NS_EWS_TYPES].TimeZoneDefinition(attributes) + end - # Build the Restriction element - # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx - # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml! - def restriction!(restriction) - @nbuild[NS_EWS_MESSAGES].Restriction { - restriction.each_pair do |k, v| - send normalize_type(k), v + # Build the Restriction element + # @see http://msdn.microsoft.com/en-us/library/aa563791.aspx + # @param [Hash] restriction a well-formatted Hash that can be fed to #build_xml! + def restriction!(restriction) + @nbuild[NS_EWS_MESSAGES].Restriction { + restriction.each_pair do |k, v| + send normalize_type(k), v + end + } end - } - end - def and_r(expr) - and_or('And', expr) - end + def and_r(expr) + and_or('And', expr) + end - def or_r(expr) - and_or('Or', expr) - end + def or_r(expr) + and_or('Or', expr) + end - def and_or(type, expr) - @nbuild[NS_EWS_TYPES].send(type) { - expr.each do |e| - type = e.keys.first - send normalize_type(type), e[type] + def and_or(type, expr) + @nbuild[NS_EWS_TYPES].send(type) { + expr.each do |e| + type = e.keys.first + send normalize_type(type), e[type] + end + } end - } - end - def not_r(expr) - @nbuild[NS_EWS_TYPES].Not { - type = expr.keys.first - send(type, expr[type]) - } - end + def not_r(expr) + @nbuild[NS_EWS_TYPES].Not { + type = expr.keys.first + send(type, expr[type]) + } + end - def contains(expr) - @nbuild[NS_EWS_TYPES].Contains( - 'ContainmentMode' => expr.delete(:containment_mode), - 'ContainmentComparison' => expr.delete(:containment_comparison) - ) { - c = expr.delete(:constant) # remove constant 1st for ordering - type = expr.keys.first - send(type, expr[type]) - constant(c) - } - end + def contains(expr) + @nbuild[NS_EWS_TYPES].Contains( + 'ContainmentMode' => expr.delete(:containment_mode), + 'ContainmentComparison' => expr.delete(:containment_comparison) + ) { + c = expr.delete(:constant) # remove constant 1st for ordering + type = expr.keys.first + send(type, expr[type]) + constant(c) + } + end - def excludes(expr) - @nbuild[NS_EWS_TYPES].Excludes { - b = expr.delete(:bitmask) # remove bitmask 1st for ordering - type = expr.keys.first - send(type, expr[type]) - bitmask(b) - } - end + def excludes(expr) + @nbuild[NS_EWS_TYPES].Excludes { + b = expr.delete(:bitmask) # remove bitmask 1st for ordering + type = expr.keys.first + send(type, expr[type]) + bitmask(b) + } + end - def exists(expr) - @nbuild[NS_EWS_TYPES].Exists { - type = expr.keys.first - send(type, expr[type]) - } - end + def exists(expr) + @nbuild[NS_EWS_TYPES].Exists { + type = expr.keys.first + send(type, expr[type]) + } + end - def bitmask(expr) - @nbuild[NS_EWS_TYPES].Bitmask('Value' => expr[:value]) - end + def bitmask(expr) + @nbuild[NS_EWS_TYPES].Bitmask('Value' => expr[:value]) + end - def is_equal_to(expr) - restriction_compare('IsEqualTo', expr) - end + def is_equal_to(expr) + restriction_compare('IsEqualTo', expr) + end - def is_greater_than(expr) - restriction_compare('IsGreaterThan', expr) - end + def is_greater_than(expr) + restriction_compare('IsGreaterThan', expr) + end - def is_greater_than_or_equal_to(expr) - restriction_compare('IsGreaterThanOrEqualTo', expr) - end + def is_greater_than_or_equal_to(expr) + restriction_compare('IsGreaterThanOrEqualTo', expr) + end - def is_less_than(expr) - restriction_compare('IsLessThan', expr) - end + def is_less_than(expr) + restriction_compare('IsLessThan', expr) + end - def is_less_than_or_equal_to(expr) - restriction_compare('IsLessThanOrEqualTo', expr) - end + def is_less_than_or_equal_to(expr) + restriction_compare('IsLessThanOrEqualTo', expr) + end - def is_not_equal_to(expr) - restriction_compare('IsNotEqualTo', expr) - end + def is_not_equal_to(expr) + restriction_compare('IsNotEqualTo', expr) + end - def restriction_compare(type, expr) - nbuild[NS_EWS_TYPES].send(type) { - expr.each do |e| - e.each_pair do |k, v| - send(k, v) - end + def restriction_compare(type, expr) + nbuild[NS_EWS_TYPES].send(type) { + expr.each do |e| + e.each_pair do |k, v| + send(k, v) + end + end + } end - } - end - def ews_types_builder - nbuild[NS_EWS_TYPES] - end + def ews_types_builder + nbuild[NS_EWS_TYPES] + end - def field_uRI(expr) - value = expr.is_a?(Hash) ? (expr[:field_uRI] || expr[:field_uri]) : expr - ews_types_builder.FieldURI('FieldURI' => value) - end + def field_uRI(expr) + value = expr.is_a?(Hash) ? (expr[:field_uRI] || expr[:field_uri]) : expr + ews_types_builder.FieldURI('FieldURI' => value) + end - alias field_uri field_uRI + alias field_uri field_uRI - def indexed_field_uRI(expr) - nbuild[NS_EWS_TYPES].IndexedFieldURI( - 'FieldURI' => expr[:field_uRI] || expr[:field_uri], - 'FieldIndex' => expr[:field_index] - ) - end + def indexed_field_uRI(expr) + nbuild[NS_EWS_TYPES].IndexedFieldURI( + 'FieldURI' => expr[:field_uRI] || expr[:field_uri], + 'FieldIndex' => expr[:field_index] + ) + end - alias indexed_field_uri indexed_field_uRI + alias indexed_field_uri indexed_field_uRI - def extended_field_uRI(expr) - nbuild[NS_EWS_TYPES].ExtendedFieldURI { - if expr[:distinguished_property_set_id] - nbuild.parent['DistinguishedPropertySetId'] = - expr[:distinguished_property_set_id] + def extended_field_uRI(expr) + nbuild[NS_EWS_TYPES].ExtendedFieldURI { + if expr[:distinguished_property_set_id] + nbuild.parent['DistinguishedPropertySetId'] = + expr[:distinguished_property_set_id] + end + nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id] + nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag] + nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name] + nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id] + nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type] + } end - nbuild.parent['PropertySetId'] = expr[:property_set_id] if expr[:property_set_id] - nbuild.parent['PropertyTag'] = expr[:property_tag] if expr[:property_tag] - nbuild.parent['PropertyName'] = expr[:property_name] if expr[:property_name] - nbuild.parent['PropertyId'] = expr[:property_id] if expr[:property_id] - nbuild.parent['PropertyType'] = expr[:property_type] if expr[:property_type] - } - end - alias extended_field_uri extended_field_uRI + alias extended_field_uri extended_field_uRI - def extended_properties!(eprops) - eprops.each { |ep| extended_property!(ep) } - end + def extended_properties!(eprops) + eprops.each { |ep| extended_property!(ep) } + end - def extended_property!(eprop) - nbuild[NS_EWS_TYPES].ExtendedProperty { - key = eprop.keys.grep(/extended/i).first - dispatch_field_uri!({ key => eprop[key] }, NS_EWS_TYPES) - if eprop[:values] - nbuild.Values { - eprop[:values].each do |v| - value! v + def extended_property!(eprop) + nbuild[NS_EWS_TYPES].ExtendedProperty { + key = eprop.keys.grep(/extended/i).first + dispatch_field_uri!({ key => eprop[key] }, NS_EWS_TYPES) + if eprop[:values] + nbuild.Values { + eprop[:values].each do |v| + value! v + end + } + elsif eprop[:value] + value! eprop[:value] end } - elsif eprop[:value] - value! eprop[:value] end - } - end - def value!(val) - nbuild[NS_EWS_TYPES].Value(val) - end + def value!(val) + nbuild[NS_EWS_TYPES].Value(val) + end - def field_uRI_or_constant(expr) - nbuild[NS_EWS_TYPES].FieldURIOrConstant { - type = expr.keys.first - send(type, expr[type]) - } - end + def field_uRI_or_constant(expr) + nbuild[NS_EWS_TYPES].FieldURIOrConstant { + type = expr.keys.first + send(type, expr[type]) + } + end - alias field_uri_or_constant field_uRI_or_constant + alias field_uri_or_constant field_uRI_or_constant - def constant(expr) - nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value]) - end + def constant(expr) + nbuild[NS_EWS_TYPES].Constant('Value' => expr[:value]) + end - # Build the CalendarView element - def calendar_view!(cal_view) - attribs = {} - cal_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end - @nbuild[NS_EWS_MESSAGES].CalendarView(attribs) - end + # Build the CalendarView element + def calendar_view!(cal_view) + attribs = {} + cal_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end + @nbuild[NS_EWS_MESSAGES].CalendarView(attribs) + end - # Build the ContactsView element - def contacts_view!(con_view) - attribs = {} - con_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end - @nbuild[NS_EWS_MESSAGES].ContactsView(attribs) - end + # Build the ContactsView element + def contacts_view!(con_view) + attribs = {} + con_view.each_pair do |k, v| attribs[camel_case(k)] = v.to_s end + @nbuild[NS_EWS_MESSAGES].ContactsView(attribs) + end - # @see https://msdn.microsoft.com/en-us/library/aa565683(v=exchg.140).aspx - def categories!(fa) - @nbuild[NS_EWS_TYPES].Categories { - @nbuild[NS_EWS_TYPES].String(fa) - } - end + # @see https://msdn.microsoft.com/en-us/library/aa565683(v=exchg.140).aspx + def categories!(fa) + @nbuild[NS_EWS_TYPES].Categories { + @nbuild[NS_EWS_TYPES].String(fa) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx - def event_types!(evtypes) - @nbuild[NS_EWS_TYPES].EventTypes { - evtypes.each do |et| - @nbuild[NS_EWS_TYPES].EventType(camel_case(et)) + # @see http://msdn.microsoft.com/en-us/library/aa579678(v=EXCHG.140).aspx + def event_types!(evtypes) + @nbuild[NS_EWS_TYPES].EventTypes { + evtypes.each do |et| + @nbuild[NS_EWS_TYPES].EventType(camel_case(et)) + end + } end - } - end - # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx - def watermark!(wmark, ns = NS_EWS_TYPES) - @nbuild[ns].Watermark(wmark) - end + # @see http://msdn.microsoft.com/en-us/library/aa565886(v=EXCHG.140).aspx + def watermark!(wmark, ns = NS_EWS_TYPES) + @nbuild[ns].Watermark(wmark) + end - # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx - def timeout!(tout) - @nbuild[NS_EWS_TYPES].Timeout(tout) - end + # @see http://msdn.microsoft.com/en-us/library/aa565201(v=EXCHG.140).aspx + def timeout!(tout) + @nbuild[NS_EWS_TYPES].Timeout(tout) + end - # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx - def status_frequency!(freq) - @nbuild[NS_EWS_TYPES].StatusFrequency(freq) - end + # @see http://msdn.microsoft.com/en-us/library/aa564048(v=EXCHG.140).aspx + def status_frequency!(freq) + @nbuild[NS_EWS_TYPES].StatusFrequency(freq) + end - # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx - def uRL!(url) - @nbuild[NS_EWS_TYPES].URL(url) - end + # @see http://msdn.microsoft.com/en-us/library/aa566309(v=EXCHG.140).aspx + def uRL!(url) + @nbuild[NS_EWS_TYPES].URL(url) + end - # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx - def subscription_id!(subid) - @nbuild.SubscriptionId(subid) - end + # @see http://msdn.microsoft.com/en-us/library/aa563790(v=EXCHG.140).aspx + def subscription_id!(subid) + @nbuild.SubscriptionId(subid) + end - # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx - def pull_subscription_request(subopts) - subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' - @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { - folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] - event_types!(subopts[:event_types]) if subopts[:event_types] - watermark!(subopts[:watermark]) if subopts[:watermark] - timeout!(subopts[:timeout]) if subopts[:timeout] - } - end + # @see http://msdn.microsoft.com/en-us/library/aa563455(v=EXCHG.140).aspx + def pull_subscription_request(subopts) + subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' + @nbuild.PullSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { + folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] + event_types!(subopts[:event_types]) if subopts[:event_types] + watermark!(subopts[:watermark]) if subopts[:watermark] + timeout!(subopts[:timeout]) if subopts[:timeout] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx - def push_subscription_request(subopts) - subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' - @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { - folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] - event_types!(subopts[:event_types]) if subopts[:event_types] - watermark!(subopts[:watermark]) if subopts[:watermark] - status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency] - uRL!(subopts[:uRL]) if subopts[:uRL] - } - end + # @see http://msdn.microsoft.com/en-us/library/aa563599(v=EXCHG.140).aspx + def push_subscription_request(subopts) + subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' + @nbuild.PushSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { + folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] + event_types!(subopts[:event_types]) if subopts[:event_types] + watermark!(subopts[:watermark]) if subopts[:watermark] + status_frequency!(subopts[:status_frequency]) if subopts[:status_frequency] + uRL!(subopts[:uRL]) if subopts[:uRL] + } + end - # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx - def streaming_subscription_request(subopts) - subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' - @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { - folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] - event_types!(subopts[:event_types]) if subopts[:event_types] - } - end + # @see http://msdn.microsoft.com/en-us/library/ff406182(v=EXCHG.140).aspx + def streaming_subscription_request(subopts) + subscribe_all = subopts[:subscribe_to_all_folders] ? 'true' : 'false' + @nbuild.StreamingSubscriptionRequest('SubscribeToAllFolders' => subscribe_all) { + folder_ids!(subopts[:folder_ids]) if subopts[:folder_ids] + event_types!(subopts[:event_types]) if subopts[:event_types] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx - def sync_state!(syncstate) - @nbuild.SyncState(syncstate) - end + # @see http://msdn.microsoft.com/en-us/library/aa565970(v=EXCHG.140).aspx + def sync_state!(syncstate) + @nbuild.SyncState(syncstate) + end - # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx - def ignore!(item_ids) - @nbuild.Ignore { - item_ids.each do |iid| - item_id!(iid) + # @see http://msdn.microsoft.com/en-us/library/aa563785(v=EXCHG.140).aspx + def ignore!(item_ids) + @nbuild.Ignore { + item_ids.each do |iid| + item_id!(iid) + end + } end - } - end - # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx - def max_changes_returned!(cnum) - @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum) - end + # @see http://msdn.microsoft.com/en-us/library/aa566325(v=EXCHG.140).aspx + def max_changes_returned!(cnum) + @nbuild[NS_EWS_MESSAGES].MaxChangesReturned(cnum) + end - # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx - def sync_scope!(scope) - @nbuild.SyncScope(scope) - end + # @see http://msdn.microsoft.com/en-us/library/dd899531(v=EXCHG.140).aspx + def sync_scope!(scope) + @nbuild.SyncScope(scope) + end - # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx - def saved_item_folder_id!(fid) - @nbuild.SavedItemFolderId { - dispatch_folder_id!(fid) - } - end + # @see http://msdn.microsoft.com/en-us/library/aa580758(v=EXCHG.140).aspx + def saved_item_folder_id!(fid) + @nbuild.SavedItemFolderId { + dispatch_folder_id!(fid) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx - def item!(item) - nbuild.Item { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + # @see http://msdn.microsoft.com/en-us/library/aa565652(v=exchg.140).aspx + def item!(item) + nbuild.Item { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def message!(item) - nbuild[NS_EWS_TYPES].Message { - extended_properties! item.delete(:extended_properties) if item[:extended_properties] - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def message!(item) + nbuild[NS_EWS_TYPES].Message { + extended_properties! item.delete(:extended_properties) if item[:extended_properties] + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def is_read!(read) - nbuild[NS_EWS_TYPES].IsRead(read) - end + def is_read!(read) + nbuild[NS_EWS_TYPES].IsRead(read) + end - def calendar_item!(item) - nbuild[NS_EWS_TYPES].CalendarItem { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def calendar_item!(item) + nbuild[NS_EWS_TYPES].CalendarItem { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def calendar_item_type!(type) - nbuild[NS_EWS_TYPES].CalendarItemType(type) - end + def calendar_item_type!(type) + nbuild[NS_EWS_TYPES].CalendarItemType(type) + end - def recurrence!(item) - nbuild[NS_EWS_TYPES].Recurrence { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def recurrence!(item) + nbuild[NS_EWS_TYPES].Recurrence { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def daily_recurrence!(item) - nbuild[NS_EWS_TYPES].DailyRecurrence { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def daily_recurrence!(item) + nbuild[NS_EWS_TYPES].DailyRecurrence { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def weekly_recurrence!(item) - nbuild[NS_EWS_TYPES].WeeklyRecurrence { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def weekly_recurrence!(item) + nbuild[NS_EWS_TYPES].WeeklyRecurrence { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def interval!(num) - nbuild[NS_EWS_TYPES].Interval(num) - end + def interval!(num) + nbuild[NS_EWS_TYPES].Interval(num) + end - def no_end_recurrence!(item) - nbuild[NS_EWS_TYPES].NoEndRecurrence { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def no_end_recurrence!(item) + nbuild[NS_EWS_TYPES].NoEndRecurrence { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def numbered_recurrence!(item) - nbuild[NS_EWS_TYPES].NumberedRecurrence { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def numbered_recurrence!(item) + nbuild[NS_EWS_TYPES].NumberedRecurrence { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def number_of_occurrences!(count) - nbuild[NS_EWS_TYPES].NumberOfOccurrences(count) - end + def number_of_occurrences!(count) + nbuild[NS_EWS_TYPES].NumberOfOccurrences(count) + end - def task!(item) - nbuild[NS_EWS_TYPES].Task { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def task!(item) + nbuild[NS_EWS_TYPES].Task { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def forward_item!(item) - nbuild[NS_EWS_TYPES].ForwardItem { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def forward_item!(item) + nbuild[NS_EWS_TYPES].ForwardItem { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def reply_to_item!(item) - nbuild[NS_EWS_TYPES].ReplyToItem { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def reply_to_item!(item) + nbuild[NS_EWS_TYPES].ReplyToItem { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def reply_all_to_item!(item) - nbuild[NS_EWS_TYPES].ReplyAllToItem { - item.each_pair { |k, v| - send("#{k}!", v) - } - } - end + def reply_all_to_item!(item) + nbuild[NS_EWS_TYPES].ReplyAllToItem { + item.each_pair { |k, v| + send("#{k}!", v) + } + } + end - def reference_item_id!(id) - nbuild[NS_EWS_TYPES].ReferenceItemId { |x| - x.parent['Id'] = id[:id] - x.parent['ChangeKey'] = id[:change_key] if id[:change_key] - } - end + def reference_item_id!(id) + nbuild[NS_EWS_TYPES].ReferenceItemId { |x| + x.parent['Id'] = id[:id] + x.parent['ChangeKey'] = id[:change_key] if id[:change_key] + } + end - def subject!(sub) - nbuild[NS_EWS_TYPES].Subject(sub) - end + def subject!(sub) + nbuild[NS_EWS_TYPES].Subject(sub) + end - def importance!(sub) - nbuild[NS_EWS_TYPES].Importance(sub) - end + def importance!(sub) + nbuild[NS_EWS_TYPES].Importance(sub) + end - def body!(b) - nbuild[NS_EWS_TYPES].Body(b[:text]) { |x| - x.parent['BodyType'] = b[:body_type] if b[:body_type] - } - end + def body!(b) + nbuild[NS_EWS_TYPES].Body(b[:text]) { |x| + x.parent['BodyType'] = b[:body_type] if b[:body_type] + } + end - def new_body_content!(b) - nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) { |x| - x.parent['BodyType'] = b[:body_type] if b[:body_type] - } - end + def new_body_content!(b) + nbuild[NS_EWS_TYPES].NewBodyContent(b[:text]) { |x| + x.parent['BodyType'] = b[:body_type] if b[:body_type] + } + end - # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx - # @param [Array] r An array of Mailbox type hashes to send to #mailbox! - def to_recipients!(r) - nbuild[NS_EWS_TYPES].ToRecipients { - r.each { |mbox| mailbox!(mbox[:mailbox]) } - } - end + # @see http://msdn.microsoft.com/en-us/library/aa563719(v=exchg.140).aspx + # @param [Array] r An array of Mailbox type hashes to send to #mailbox! + def to_recipients!(r) + nbuild[NS_EWS_TYPES].ToRecipients { + r.each { |mbox| mailbox!(mbox[:mailbox]) } + } + end - def cc_recipients!(r) - nbuild[NS_EWS_TYPES].CcRecipients { - r.each { |mbox| mailbox!(mbox[:mailbox]) } - } - end + def cc_recipients!(r) + nbuild[NS_EWS_TYPES].CcRecipients { + r.each { |mbox| mailbox!(mbox[:mailbox]) } + } + end - def bcc_recipients!(r) - nbuild[NS_EWS_TYPES].BccRecipients { - r.each { |mbox| mailbox!(mbox[:mailbox]) } - } - end + def bcc_recipients!(r) + nbuild[NS_EWS_TYPES].BccRecipients { + r.each { |mbox| mailbox!(mbox[:mailbox]) } + } + end - def from!(f) - nbuild[NS_EWS_TYPES].From { - mailbox! f - } - end + def from!(f) + nbuild[NS_EWS_TYPES].From { + mailbox! f + } + end - def required_attendees!(attendees) - nbuild[NS_EWS_TYPES].RequiredAttendees { - attendees.each { |a| attendee!(a[:attendee]) } - } - end + def required_attendees!(attendees) + nbuild[NS_EWS_TYPES].RequiredAttendees { + attendees.each { |a| attendee!(a[:attendee]) } + } + end - def optional_attendees!(attendees) - nbuild[NS_EWS_TYPES].OptionalAttendees { - attendees.each { |a| attendee!(a[:attendee]) } - } - end + def optional_attendees!(attendees) + nbuild[NS_EWS_TYPES].OptionalAttendees { + attendees.each { |a| attendee!(a[:attendee]) } + } + end - def resources!(attendees) - nbuild[NS_EWS_TYPES].Resources { - attendees.each { |a| attendee!(a[:attendee]) } - } - end + def resources!(attendees) + nbuild[NS_EWS_TYPES].Resources { + attendees.each { |a| attendee!(a[:attendee]) } + } + end - # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx - def attendee!(a) - nbuild[NS_EWS_TYPES].Attendee { - mailbox!(a[:mailbox]) - } - end + # @todo support ResponseType, LastResponseTime: http://msdn.microsoft.com/en-us/library/aa580339.aspx + def attendee!(a) + nbuild[NS_EWS_TYPES].Attendee { + mailbox!(a[:mailbox]) + } + end - def start!(st) - nbuild[NS_EWS_TYPES].Start(st[:text]) - end + def start!(st) + nbuild[NS_EWS_TYPES].Start(st[:text]) + end - def end!(et) - nbuild[NS_EWS_TYPES].End(et[:text]) - end + def end!(et) + nbuild[NS_EWS_TYPES].End(et[:text]) + end - def start_date!(sd) - nbuild[NS_EWS_TYPES].StartDate sd[:text] - end + def start_date!(sd) + nbuild[NS_EWS_TYPES].StartDate sd[:text] + end - def due_date!(dd) - nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text]) - end + def due_date!(dd) + nbuild[NS_EWS_TYPES].DueDate format_time(dd[:text]) + end - def location!(loc) - nbuild[NS_EWS_TYPES].Location(loc) - end + def location!(loc) + nbuild[NS_EWS_TYPES].Location(loc) + end - def is_all_day_event!(all_day) - nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day) - end + def is_all_day_event!(all_day) + nbuild[NS_EWS_TYPES].IsAllDayEvent(all_day) + end - def is_response_requested!(response_requested) - nbuild[NS_EWS_TYPES].IsResponseRequested(response_requested) - end + def is_response_requested!(response_requested) + nbuild[NS_EWS_TYPES].IsResponseRequested(response_requested) + end - def reminder_is_set!(reminder) - nbuild[NS_EWS_TYPES].ReminderIsSet reminder - end + def reminder_is_set!(reminder) + nbuild[NS_EWS_TYPES].ReminderIsSet reminder + end - def reminder_due_by!(date) - nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date) - end + def reminder_due_by!(date) + nbuild[NS_EWS_TYPES].ReminderDueBy format_time(date) + end - def reminder_minutes_before_start!(minutes) - nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes - end + def reminder_minutes_before_start!(minutes) + nbuild[NS_EWS_TYPES].ReminderMinutesBeforeStart minutes + end - # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx - # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData] - # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData] - def legacy_free_busy_status!(state) - nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state) - end + # @see http://msdn.microsoft.com/en-us/library/aa566143(v=exchg.150).aspx + # possible values Exchange Server 2010 = [Free, Tentative, Busy, OOF, NoData] + # Exchange Server 2013 = [Free, Tentative, Busy, OOF, WorkingElsewhere, NoData] + def legacy_free_busy_status!(state) + nbuild[NS_EWS_TYPES].LegacyFreeBusyStatus(state) + end - # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx - def item_changes!(changes) - nbuild.ItemChanges { - changes.each do |chg| - item_change!(chg) + # @see http://msdn.microsoft.com/en-us/library/aa565428(v=exchg.140).aspx + def item_changes!(changes) + nbuild.ItemChanges { + changes.each do |chg| + item_change!(chg) + end + } end - } - end - # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx - def item_change!(change) - @nbuild[NS_EWS_TYPES].ItemChange { - updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly - dispatch_item_id!(change) - updates!(updates) - } - end + # @see http://msdn.microsoft.com/en-us/library/aa581081(v=exchg.140).aspx + def item_change!(change) + @nbuild[NS_EWS_TYPES].ItemChange { + updates = change.delete(:updates) # Remove updates so dispatch_item_id works correctly + dispatch_item_id!(change) + updates!(updates) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx - def updates!(updates) - @nbuild[NS_EWS_TYPES].Updates { - updates.each do |update| - dispatch_update_type!(update) + # @see http://msdn.microsoft.com/en-us/library/aa581074(v=exchg.140).aspx + def updates!(updates) + @nbuild[NS_EWS_TYPES].Updates { + updates.each do |update| + dispatch_update_type!(update) + end + } end - } - end - # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx - def append_to_item_field!(upd) - uri = upd.select { |k, _v| k =~ /_uri/i } - raise EwsBadArgumentError, 'Bad argument given for AppendToItemField.' if uri.keys.length != 1 + # @see http://msdn.microsoft.com/en-us/library/aa581317(v=exchg.140).aspx + def append_to_item_field!(upd) + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for AppendToItemField.' if uri.keys.length != 1 - upd.delete(uri.keys.first) - @nbuild.AppendToItemField { - dispatch_field_uri!(uri) - dispatch_field_item!(upd) - } - end + upd.delete(uri.keys.first) + @nbuild.AppendToItemField { + dispatch_field_uri!(uri) + dispatch_field_item!(upd) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx - def set_item_field!(upd) - uri = upd.select { |k, _v| k =~ /_uri/i } - raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 + # @see http://msdn.microsoft.com/en-us/library/aa581487(v=exchg.140).aspx + def set_item_field!(upd) + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 - upd.delete(uri.keys.first) - @nbuild[NS_EWS_TYPES].SetItemField { - dispatch_field_uri!(uri, NS_EWS_TYPES) - dispatch_field_item!(upd, NS_EWS_TYPES) - } - end + upd.delete(uri.keys.first) + @nbuild[NS_EWS_TYPES].SetItemField { + dispatch_field_uri!(uri, NS_EWS_TYPES) + dispatch_field_item!(upd, NS_EWS_TYPES) + } + end - # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx - def delete_item_field!(upd) - uri = upd.select { |k, _v| k =~ /_uri/i } - raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 + # @see http://msdn.microsoft.com/en-us/library/aa580330(v=exchg.140).aspx + def delete_item_field!(upd) + uri = upd.select { |k, _v| k =~ /_uri/i } + raise EwsBadArgumentError, 'Bad argument given for SetItemField.' if uri.keys.length != 1 - @nbuild[NS_EWS_TYPES].DeleteItemField { - dispatch_field_uri!(uri, NS_EWS_TYPES) - } - end + @nbuild[NS_EWS_TYPES].DeleteItemField { + dispatch_field_uri!(uri, NS_EWS_TYPES) + } + end - # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx - def return_new_item_ids!(retval) - @nbuild.ReturnNewItemIds(retval) - end + # @see http://msdn.microsoft.com/en-us/library/ff709497(v=exchg.140).aspx + def return_new_item_ids!(retval) + @nbuild.ReturnNewItemIds(retval) + end - def inline_attachment!(fa) - @nbuild[NS_EWS_TYPES].FileAttachment { - @nbuild[NS_EWS_TYPES].Name(fa.name) - @nbuild[NS_EWS_TYPES].ContentId(fa.name) - @nbuild[NS_EWS_TYPES].IsInline(true) - @nbuild[NS_EWS_TYPES].Content(fa.content) - } - end + def inline_attachment!(fa) + @nbuild[NS_EWS_TYPES].FileAttachment { + @nbuild[NS_EWS_TYPES].Name(fa.name) + @nbuild[NS_EWS_TYPES].ContentId(fa.name) + @nbuild[NS_EWS_TYPES].IsInline(true) + @nbuild[NS_EWS_TYPES].Content(fa.content) + } + end - def file_attachment!(fa) - @nbuild[NS_EWS_TYPES].FileAttachment { - @nbuild[NS_EWS_TYPES].Name(fa.name) - @nbuild[NS_EWS_TYPES].Content(fa.content) - } - end + def file_attachment!(fa) + @nbuild[NS_EWS_TYPES].FileAttachment { + @nbuild[NS_EWS_TYPES].Name(fa.name) + @nbuild[NS_EWS_TYPES].Content(fa.content) + } + end - def item_attachment!(ia) - @nbuild[NS_EWS_TYPES].ItemAttachment { - @nbuild[NS_EWS_TYPES].Name(ia.name) - @nbuild[NS_EWS_TYPES].Item { - item_id!(ia.item) - } - } - end + def item_attachment!(ia) + @nbuild[NS_EWS_TYPES].ItemAttachment { + @nbuild[NS_EWS_TYPES].Name(ia.name) + @nbuild[NS_EWS_TYPES].Item { + item_id!(ia.item) + } + } + end - # Build the AttachmentIds element - # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx - def attachment_ids!(aids) - @nbuild.AttachmentIds { - @nbuild.parent.default_namespace = @default_ns - aids.each do |aid| - attachment_id!(aid) + # Build the AttachmentIds element + # @see http://msdn.microsoft.com/en-us/library/aa580686.aspx + def attachment_ids!(aids) + @nbuild.AttachmentIds { + @nbuild.parent.default_namespace = @default_ns + aids.each do |aid| + attachment_id!(aid) + end + } end - } - end - # Build the AttachmentId element - # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx - def attachment_id!(aid) - attribs = { 'Id' => aid } - @nbuild[NS_EWS_TYPES].AttachmentId(attribs) - end + # Build the AttachmentId element + # @see http://msdn.microsoft.com/en-us/library/aa580764.aspx + def attachment_id!(aid) + attribs = { 'Id' => aid } + @nbuild[NS_EWS_TYPES].AttachmentId(attribs) + end - def user_configuration_name!(cfg_name) - attribs = { 'Name' => cfg_name.delete(:name) } - @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) { - fid = cfg_name.keys.first - send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key] - } - end + def user_configuration_name!(cfg_name) + attribs = { 'Name' => cfg_name.delete(:name) } + @nbuild[NS_EWS_MESSAGES].UserConfigurationName(attribs) { + fid = cfg_name.keys.first + send "#{fid}!", cfg_name[fid][:id], cfg_name[fid][:change_key] + } + end - def user_configuration_properties!(cfg_prop) - @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop) - end + def user_configuration_properties!(cfg_prop) + @nbuild[NS_EWS_MESSAGES].UserConfigurationProperties(cfg_prop) + end - # ---------------------- Helpers -------------------- # - - # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly - # @param [Hash] fid A folder_id - # Ex: {:id => myid, :change_key => ck} - def dispatch_folder_id!(fid) - if fid[:id].is_a?(String) - folder_id!(fid[:id], fid[:change_key]) - elsif fid[:id].is_a?(Symbol) - distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as]) - else - raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}" - end - end + # ---------------------- Helpers -------------------- # - # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId - # @param [Hash] iid The item id of some type - def dispatch_item_id!(iid) - type = iid.keys.first - item = iid[type] - case type - when :item_id - item_id!(item) - when :occurrence_item_id - occurrence_item_id!(item) - when :recurring_master_item_id - recurring_master_item_id!(item) - else - raise EwsBadArgumentError, "Bad ItemId type. #{type}" - end - end + # A helper method to dispatch to a FolderId or DistinguishedFolderId correctly + # @param [Hash] fid A folder_id + # Ex: {:id => myid, :change_key => ck} + def dispatch_folder_id!(fid) + if fid[:id].is_a?(String) + folder_id!(fid[:id], fid[:change_key]) + elsif fid[:id].is_a?(Symbol) + distinguished_folder_id!(fid[:id], fid[:change_key], fid[:act_as]) + else + raise EwsBadArgumentError, "Bad argument given for a FolderId. #{fid[:id].class}" + end + end - # A helper method to dispatch to a AppendToItemField, SetItemField, or - # DeleteItemField - # @param [Hash] update An update of some type - def dispatch_update_type!(update) - type = update.keys.first - upd = update[type] - case type - when :append_to_item_field - append_to_item_field!(upd) - when :set_item_field - set_item_field!(upd) - when :delete_item_field - delete_item_field!(upd) - else - raise EwsBadArgumentError, "Bad Update type. #{type}" - end - end + # A helper method to dispatch to an ItemId, OccurrenceItemId, or a RecurringMasterItemId + # @param [Hash] iid The item id of some type + def dispatch_item_id!(iid) + type = iid.keys.first + item = iid[type] + case type + when :item_id + item_id!(item) + when :occurrence_item_id + occurrence_item_id!(item) + when :recurring_master_item_id + recurring_master_item_id!(item) + else + raise EwsBadArgumentError, "Bad ItemId type. #{type}" + end + end - # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI - # @todo Implement ExtendedFieldURI - def dispatch_field_uri!(uri, ns = NS_EWS_MESSAGES) - type = uri.keys.first - vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]] - case type - when :field_uRI, :field_uri - vals.each do |val| - value = val.is_a?(Hash) ? val[type] : val - nbuild[ns].FieldURI('FieldURI' => value) - end - when :indexed_field_uRI, :indexed_field_uri - vals.each do |val| - nbuild[ns].IndexedFieldURI( - 'FieldURI' => val[:field_uRI] || val[:field_uri], - 'FieldIndex' => val[:field_index] - ) + # A helper method to dispatch to a AppendToItemField, SetItemField, or + # DeleteItemField + # @param [Hash] update An update of some type + def dispatch_update_type!(update) + type = update.keys.first + upd = update[type] + case type + when :append_to_item_field + append_to_item_field!(upd) + when :set_item_field + set_item_field!(upd) + when :delete_item_field + delete_item_field!(upd) + else + raise EwsBadArgumentError, "Bad Update type. #{type}" + end end - when :extended_field_uRI, :extended_field_uri - vals.each do |val| - nbuild[ns].ExtendedFieldURI { - if val[:distinguished_property_set_id] - nbuild.parent['DistinguishedPropertySetId'] = - val[:distinguished_property_set_id] + + # A helper to dispatch to a FieldURI, IndexedFieldURI, or an ExtendedFieldURI + # @todo Implement ExtendedFieldURI + def dispatch_field_uri!(uri, ns = NS_EWS_MESSAGES) + type = uri.keys.first + vals = uri[type].is_a?(Array) ? uri[type] : [uri[type]] + case type + when :field_uRI, :field_uri + vals.each do |val| + value = val.is_a?(Hash) ? val[type] : val + nbuild[ns].FieldURI('FieldURI' => value) end - nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id] - nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag] - nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name] - nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id] - nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type] - } + when :indexed_field_uRI, :indexed_field_uri + vals.each do |val| + nbuild[ns].IndexedFieldURI( + 'FieldURI' => val[:field_uRI] || val[:field_uri], + 'FieldIndex' => val[:field_index] + ) + end + when :extended_field_uRI, :extended_field_uri + vals.each do |val| + nbuild[ns].ExtendedFieldURI { + if val[:distinguished_property_set_id] + nbuild.parent['DistinguishedPropertySetId'] = + val[:distinguished_property_set_id] + end + nbuild.parent['PropertySetId'] = val[:property_set_id] if val[:property_set_id] + nbuild.parent['PropertyTag'] = val[:property_tag] if val[:property_tag] + nbuild.parent['PropertyName'] = val[:property_name] if val[:property_name] + nbuild.parent['PropertyId'] = val[:property_id] if val[:property_id] + nbuild.parent['PropertyType'] = val[:property_type] if val[:property_type] + } + end + else + raise EwsBadArgumentError, "Bad URI type. #{type}" + end end - else - raise EwsBadArgumentError, "Bad URI type. #{type}" - end - end - # Insert item, enforce xmlns attribute if prefix is present - def dispatch_field_item!(item, ns_prefix = nil) - item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix - build_xml!(item) - end + # Insert item, enforce xmlns attribute if prefix is present + def dispatch_field_item!(item, ns_prefix = nil) + item.values.first[:xmlns_attribute] = ns_prefix if ns_prefix + build_xml!(item) + end - def room_list!(cfg_prop) - @nbuild[NS_EWS_MESSAGES].RoomList { - email_address!(cfg_prop) - } - end + def room_list!(cfg_prop) + @nbuild[NS_EWS_MESSAGES].RoomList { + email_address!(cfg_prop) + } + end - def room_lists! - @nbuild[NS_EWS_MESSAGES].GetRoomLists - end + def room_lists! + @nbuild[NS_EWS_MESSAGES].GetRoomLists + end - def accept_item!(opts) - @nbuild[NS_EWS_TYPES].AcceptItem { - sensitivity!(opts) - body!(opts) if opts[:text] - reference_item_id!(opts) - } - end + def accept_item!(opts) + @nbuild[NS_EWS_TYPES].AcceptItem { + sensitivity!(opts) + body!(opts) if opts[:text] + reference_item_id!(opts) + } + end - def tentatively_accept_item!(opts) - @nbuild[NS_EWS_TYPES].TentativelyAcceptItem { - sensitivity!(opts) - body!(opts) if opts[:text] - reference_item_id!(opts) - } - end + def tentatively_accept_item!(opts) + @nbuild[NS_EWS_TYPES].TentativelyAcceptItem { + sensitivity!(opts) + body!(opts) if opts[:text] + reference_item_id!(opts) + } + end - def decline_item!(opts) - @nbuild[NS_EWS_TYPES].DeclineItem { - sensitivity!(opts) - body!(opts) if opts[:text] - reference_item_id!(opts) - } - end + def decline_item!(opts) + @nbuild[NS_EWS_TYPES].DeclineItem { + sensitivity!(opts) + body!(opts) if opts[:text] + reference_item_id!(opts) + } + end - def sensitivity!(value) - nbuild[NS_EWS_TYPES].Sensitivity(value[:sensitivity]) - end + def sensitivity!(value) + nbuild[NS_EWS_TYPES].Sensitivity(value[:sensitivity]) + end - private + private - def parent_namespace(node) - node.parent.namespace_definitions.find { |ns| ns.prefix == NS_SOAP } - end + def parent_namespace(node) + node.parent.namespace_definitions.find { |ns| ns.prefix == NS_SOAP } + end - def set_version_header!(version) - return unless version && !(version == 'none') + def set_version_header!(version) + return unless version && !(version == 'none') - nbuild[NS_EWS_TYPES].RequestServerVersion { |x| - x.parent['Version'] = version - } - end + nbuild[NS_EWS_TYPES].RequestServerVersion { |x| + x.parent['Version'] = version + } + end - def set_impersonation!(type, address) - return unless type && type != '' + def set_impersonation!(type, address) + return unless type && type != '' - nbuild[NS_EWS_TYPES].ExchangeImpersonation { - nbuild[NS_EWS_TYPES].ConnectingSID { - nbuild[NS_EWS_TYPES].method_missing type, address - } - } - end + nbuild[NS_EWS_TYPES].ExchangeImpersonation { + nbuild[NS_EWS_TYPES].ConnectingSID { + nbuild[NS_EWS_TYPES].method_missing type, address + } + } + end - # Set TimeZoneContext Header - # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name} - def set_time_zone_context_header!(time_zone_def) - return unless time_zone_def + # Set TimeZoneContext Header + # @param time_zone_def [Hash] !{id: time_zone_identifier, name: time_zone_name} + def set_time_zone_context_header!(time_zone_def) + return unless time_zone_def - nbuild[NS_EWS_TYPES].TimeZoneContext do - time_zone_definition! time_zone_def - end - end + nbuild[NS_EWS_TYPES].TimeZoneContext do + time_zone_definition! time_zone_def + end + end - def meeting_time_zone!(mtz) - nbuild[NS_EWS_TYPES].MeetingTimeZone do |x| - x.parent['TimeZoneName'] = mtz[:time_zone_name] if mtz[:time_zone_name] - nbuild[NS_EWS_TYPES].BaseOffset(mtz[:base_offset][:text]) if mtz[:base_offset] - end - end + def meeting_time_zone!(mtz) + nbuild[NS_EWS_TYPES].MeetingTimeZone do |x| + x.parent['TimeZoneName'] = mtz[:time_zone_name] if mtz[:time_zone_name] + nbuild[NS_EWS_TYPES].BaseOffset(mtz[:base_offset][:text]) if mtz[:base_offset] + end + end - # some methods need special naming so they use the '_r' suffix like 'and' - def normalize_type(type) - case type - when :and, :or, :not - "#{type}_r".to_sym - else - type - end - end + # some methods need special naming so they use the '_r' suffix like 'and' + def normalize_type(type) + case type + when :and, :or, :not + "#{type}_r".to_sym + else + type + end + end - def format_time(time) - case time - when Time, Date, DateTime - time.to_datetime.new_offset(0).iso8601 - when String - begin - DateTime.parse(time).new_offset(0).iso8601 - rescue ArgumentError - raise EwsBadArgumentError, "Invalid Time argument (#{time})" - end - else - raise EwsBadArgumentError, "Invalid Time argument (#{time})" + def format_time(time) + case time + when Time, Date, DateTime + time.to_datetime.new_offset(0).iso8601 + when String + begin + DateTime.parse(time).new_offset(0).iso8601 + rescue ArgumentError + raise EwsBadArgumentError, "Invalid Time argument (#{time})" + end + else + raise EwsBadArgumentError, "Invalid Time argument (#{time})" + end + end end end end diff --git a/lib/ews/soap/ews_response.rb b/lib/ews/soap/ews_response.rb index e75508fd..975554d0 100644 --- a/lib/ews/soap/ews_response.rb +++ b/lib/ews/soap/ews_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,60 +16,64 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # A Generic Class for SOAP returns. - class EwsResponse - include Viewpoint::StringUtils +module Viewpoint + module EWS + module SOAP + # A Generic Class for SOAP returns. + class EwsResponse + include Viewpoint::StringUtils - def initialize(sax_hash) - @resp = sax_hash - simplify! - end + def initialize(sax_hash) + @resp = sax_hash + simplify! + end - def envelope - @resp[:envelope][:elems] - end + def envelope + @resp[:envelope][:elems] + end - def header - envelope[0][:header][:elems] - end + def header + envelope[0][:header][:elems] + end - def body - envelope[1][:body][:elems] - end + def body + envelope[1][:body][:elems] + end - def response - body[0] - end + def response + body[0] + end - def response_messages - return @response_messages if @response_messages + def response_messages + return @response_messages if @response_messages - @response_messages = [] - response_type = response.keys.first - response[response_type][:elems][0][:response_messages][:elems].each do |rm| - response_message_type = rm.keys[0] - rm_klass = class_by_name(response_message_type) - @response_messages << rm_klass.new(rm) - end - @response_messages - end + @response_messages = [] + response_type = response.keys.first + response[response_type][:elems][0][:response_messages][:elems].each do |rm| + response_message_type = rm.keys[0] + rm_klass = class_by_name(response_message_type) + @response_messages << rm_klass.new(rm) + end + @response_messages + end - private + private - def simplify! - response_type = response.keys.first - response[response_type][:elems][0][:response_messages][:elems].each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) - end - end + def simplify! + response_type = response.keys.first + response[response_type][:elems][0][:response_messages][:elems].each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) + end + end - def class_by_name(cname) - cname = camel_case(cname) if cname.instance_of? Symbol - Viewpoint::EWS::SOAP.const_get(cname) - rescue NameError - ResponseMessage + def class_by_name(cname) + cname = camel_case(cname) if cname.instance_of? Symbol + Viewpoint::EWS::SOAP.const_get(cname) + rescue NameError + ResponseMessage + end + end end end end diff --git a/lib/ews/soap/ews_soap_availability_response.rb b/lib/ews/soap/ews_soap_availability_response.rb index 5bfa9c1d..20a131d7 100644 --- a/lib/ews/soap/ews_soap_availability_response.rb +++ b/lib/ews/soap/ews_soap_availability_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,39 +16,43 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # This is a speciality response class to handle the idiosynracies of - # Availability responses. - # @attr_reader [String] :message The text from the EWS element - class EwsSoapAvailabilityResponse < EwsSoapResponse - def response_messages - nil - end +module Viewpoint + module EWS + module SOAP + # This is a speciality response class to handle the idiosynracies of + # Availability responses. + # @attr_reader [String] :message The text from the EWS element + class EwsSoapAvailabilityResponse < EwsSoapResponse + def response_messages + nil + end - def response - body[0][response_key] - end + def response + body[0][response_key] + end - def response_message - key = response.keys.first - response[key] - end + def response_message + key = response.keys.first + response[key] + end - def response_code - response_message[:elems][:response_code][:text] - end - alias code response_code + def response_code + response_message[:elems][:response_code][:text] + end + alias code response_code - def response_key - body[0].keys.first - end + def response_key + body[0].keys.first + end - private + private - def simplify! - key = response_key - body[0][key] = body[0][key][:elems].inject(:merge) - response_message[:elems] = response_message[:elems].inject(:merge) + def simplify! + key = response_key + body[0][key] = body[0][key][:elems].inject(:merge) + response_message[:elems] = response_message[:elems].inject(:merge) + end + end end end end diff --git a/lib/ews/soap/ews_soap_free_busy_response.rb b/lib/ews/soap/ews_soap_free_busy_response.rb index 33ae866d..34eaf15c 100644 --- a/lib/ews/soap/ews_soap_free_busy_response.rb +++ b/lib/ews/soap/ews_soap_free_busy_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is a cotribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Mark McCahill @@ -15,100 +16,104 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class EwsSoapFreeBusyResponse < EwsSoapResponse - def initialize(sax_hash) - @resp = sax_hash - simplify! - end - - def envelope - @resp[:envelope][:elems] - end - - def header - envelope[0][:header][:elems] - end - - def body - envelope[1][:body][:elems] - end - - def get_user_availability_response - body.first[:get_user_availability_response][:elems].first[:free_busy_response_array][:elems].first[:free_busy_response][:elems] - end - - def response - body - end - - def calendar_event_array - result = find_in_hash_list(get_user_availability_response[1][:free_busy_view][:elems], :calendar_event_array) - result ? result[:elems] : [] - end - - def working_hours - get_user_availability_response[1][:free_busy_view][:elems][2][:working_hours][:elems] - end - - def response_message - find_in_hash_list(get_user_availability_response, :response_message) - end - - def response_class - response_message[:attribs][:response_class] - end - alias status response_class - - def response_code - result = find_in_hash_list(response_message[:elems], :response_code) - result ? result[:text] : nil - end - alias code response_code - - def response_message_text - guard_hash response_message[:elems], %i[message_text text] - end - alias message response_message_text - - def response_key - response_message[:elems] - end - - def success? - response_class == 'Success' - end - - private - - def simplify! - # key = response_key - # body[0][key] = body[0][key][:elems].inject(:merge) - # response_message[:elems] = response_message[:elems].inject(:merge) - end - - # If the keys don't exist in the Hash return nil - # @param[Hash] hsh - # @param[Array] keys keys to follow in the array - # @return [Object, nil] - def guard_hash(hsh, keys) - key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) - - if keys.empty? - hsh[key] - else - guard_hash hsh[key], keys +module Viewpoint + module EWS + module SOAP + class EwsSoapFreeBusyResponse < EwsSoapResponse + def initialize(sax_hash) + @resp = sax_hash + simplify! + end + + def envelope + @resp[:envelope][:elems] + end + + def header + envelope[0][:header][:elems] + end + + def body + envelope[1][:body][:elems] + end + + def get_user_availability_response + body.first[:get_user_availability_response][:elems].first[:free_busy_response_array][:elems].first[:free_busy_response][:elems] + end + + def response + body + end + + def calendar_event_array + result = find_in_hash_list(get_user_availability_response[1][:free_busy_view][:elems], :calendar_event_array) + result ? result[:elems] : [] + end + + def working_hours + get_user_availability_response[1][:free_busy_view][:elems][2][:working_hours][:elems] + end + + def response_message + find_in_hash_list(get_user_availability_response, :response_message) + end + + def response_class + response_message[:attribs][:response_class] + end + alias status response_class + + def response_code + result = find_in_hash_list(response_message[:elems], :response_code) + result ? result[:text] : nil + end + alias code response_code + + def response_message_text + guard_hash response_message[:elems], %i[message_text text] + end + alias message response_message_text + + def response_key + response_message[:elems] + end + + def success? + response_class == 'Success' + end + + private + + def simplify! + # key = response_key + # body[0][key] = body[0][key][:elems].inject(:merge) + # response_message[:elems] = response_message[:elems].inject(:merge) + end + + # If the keys don't exist in the Hash return nil + # @param[Hash] hsh + # @param[Array] keys keys to follow in the array + # @return [Object, nil] + def guard_hash(hsh, keys) + key = keys.shift + return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) + + if keys.empty? + hsh[key] + else + guard_hash hsh[key], keys + end + end + + # Find the first element in a list of hashes or return nil + # Example: + # find_in_hash_list([{:foo => :bar}, {:bar => :baz}], :foo) + # => :bar + def find_in_hash_list(collection, key) + result = collection.find { |hsh| hsh.keys.include?(key) } + result ? result[key] : nil + end end end - - # Find the first element in a list of hashes or return nil - # Example: - # find_in_hash_list([{:foo => :bar}, {:bar => :baz}], :foo) - # => :bar - def find_in_hash_list(collection, key) - result = collection.find { |hsh| hsh.keys.include?(key) } - result ? result[key] : nil - end end end diff --git a/lib/ews/soap/ews_soap_response.rb b/lib/ews/soap/ews_soap_response.rb index ecdf8768..e92917bd 100644 --- a/lib/ews/soap/ews_soap_response.rb +++ b/lib/ews/soap/ews_soap_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,81 +16,85 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # A Generic Class for SOAP returns. - # @attr_reader [String] :message The text from the EWS element - class EwsSoapResponse - def initialize(sax_hash) - @resp = sax_hash - simplify! - end +module Viewpoint + module EWS + module SOAP + # A Generic Class for SOAP returns. + # @attr_reader [String] :message The text from the EWS element + class EwsSoapResponse + def initialize(sax_hash) + @resp = sax_hash + simplify! + end - def envelope - @resp[:envelope][:elems] - end + def envelope + @resp[:envelope][:elems] + end - def header - envelope[0][:header][:elems] - end + def header + envelope[0][:header][:elems] + end - def body - envelope[1][:body][:elems] - end + def body + envelope[1][:body][:elems] + end - def response - body[0] - end + def response + body[0] + end - def response_messages - key = response.keys.first - response[key][:elems].find { |e| e.keys.include? :response_messages }[:response_messages][:elems] - end + def response_messages + key = response.keys.first + response[key][:elems].find { |e| e.keys.include? :response_messages }[:response_messages][:elems] + end - def response_message - key = response_messages[0].keys.first - response_messages[0][key] - end + def response_message + key = response_messages[0].keys.first + response_messages[0][key] + end - def response_class - response_message[:attribs][:response_class] - end - alias status response_class + def response_class + response_message[:attribs][:response_class] + end + alias status response_class - def response_code - response_message[:elems][:response_code][:text] - end - alias code response_code + def response_code + response_message[:elems][:response_code][:text] + end + alias code response_code - def response_message_text - guard_hash response_message[:elems], %i[message_text text] - end - alias message response_message_text + def response_message_text + guard_hash response_message[:elems], %i[message_text text] + end + alias message response_message_text - def success? - response_class == 'Success' - end + def success? + response_class == 'Success' + end - private + private - def simplify! - response_messages.each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) - end - end + def simplify! + response_messages.each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) + end + end + + # If the keys don't exist in the Hash return nil + # @param[Hash] hsh + # @param[Array] keys keys to follow in the array + # @return [Object, nil] + def guard_hash(hsh, keys) + key = keys.shift + return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) - # If the keys don't exist in the Hash return nil - # @param[Hash] hsh - # @param[Array] keys keys to follow in the array - # @return [Object, nil] - def guard_hash(hsh, keys) - key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) - - if keys.empty? - hsh[key] - else - guard_hash hsh[key], keys + if keys.empty? + hsh[key] + else + guard_hash hsh[key], keys + end + end end end end diff --git a/lib/ews/soap/ews_soap_room_response.rb b/lib/ews/soap/ews_soap_room_response.rb index cb00ff1f..7a5ab25b 100644 --- a/lib/ews/soap/ews_soap_room_response.rb +++ b/lib/ews/soap/ews_soap_room_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock @@ -15,33 +16,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # A class for roomlists SOAP returns. - # @attr_reader [String] :message The text from the EWS element - class EwsSoapRoomResponse < EwsSoapResponse - def response_messages - key = response.keys.first - subresponse = response[key][:elems][1] - response_class = subresponse.keys.first - subresponse[response_class][:elems] - end +module Viewpoint + module EWS + module SOAP + # A class for roomlists SOAP returns. + # @attr_reader [String] :message The text from the EWS element + class EwsSoapRoomResponse < EwsSoapResponse + def response_messages + key = response.keys.first + subresponse = response[key][:elems][1] + response_class = subresponse.keys.first + subresponse[response_class][:elems] + end - def roomsArray - response[:get_rooms_response][:elems][1][:rooms][:elems] - end + def roomsArray + response[:get_rooms_response][:elems][1][:rooms][:elems] + end - def success? - response.first[1][:attribs][:response_class] == 'Success' - end + def success? + response.first[1][:attribs][:response_class] == 'Success' + end - private + private - def simplify! - return unless response_messages + def simplify! + return unless response_messages - response_messages.each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) + response_messages.each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) + end + end end end end diff --git a/lib/ews/soap/ews_soap_roomlist_response.rb b/lib/ews/soap/ews_soap_roomlist_response.rb index 9a855558..138abee2 100644 --- a/lib/ews/soap/ews_soap_roomlist_response.rb +++ b/lib/ews/soap/ews_soap_roomlist_response.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is a contribution to Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2013 Camille Baldock @@ -15,33 +16,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # A class for roomlists SOAP returns. - # @attr_reader [String] :message The text from the EWS element - class EwsSoapRoomlistResponse < EwsSoapResponse - def response_messages - key = response.keys.first - subresponse = response[key][:elems][1] - response_class = subresponse.keys.first - subresponse[response_class][:elems] - end +module Viewpoint + module EWS + module SOAP + # A class for roomlists SOAP returns. + # @attr_reader [String] :message The text from the EWS element + class EwsSoapRoomlistResponse < EwsSoapResponse + def response_messages + key = response.keys.first + subresponse = response[key][:elems][1] + response_class = subresponse.keys.first + subresponse[response_class][:elems] + end - def roomListsArray - response[:get_room_lists_response][:elems][1][:room_lists][:elems] - end + def roomListsArray + response[:get_room_lists_response][:elems][1][:room_lists][:elems] + end - def success? - response.first[1][:attribs][:response_class] == 'Success' - end + def success? + response.first[1][:attribs][:response_class] == 'Success' + end - private + private - def simplify! - return unless response_messages + def simplify! + return unless response_messages - response_messages.each do |rm| - key = rm.keys.first - rm[key][:elems] = rm[key][:elems].inject(&:merge) + response_messages.each do |rm| + key = rm.keys.first + rm[key][:elems] = rm[key][:elems].inject(&:merge) + end + end end end end diff --git a/lib/ews/soap/exchange_availability.rb b/lib/ews/soap/exchange_availability.rb index 454ad529..6d329258 100644 --- a/lib/ews/soap/exchange_availability.rb +++ b/lib/ews/soap/exchange_availability.rb @@ -1,58 +1,63 @@ # frozen_string_literal: true -module Viewpoint::EWS::SOAP - # Exchange Availability operations as listed in the EWS Documentation. - # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx - module ExchangeAvailability - include Viewpoint::EWS::SOAP - # -------------- Availability Operations ------------- +module Viewpoint + module EWS + module SOAP + # Exchange Availability operations as listed in the EWS Documentation. + # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx + module ExchangeAvailability + include Viewpoint::EWS::SOAP - # Gets a mailbox user's Out of Office (OOF) settings and messages. - # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx - # @param [Hash] opts - # @option opts [String] :address the email address of the user - # @option opts [String] :name the user display name (optional) - # @option opts [String] :routing_type the routing protocol (optional and stupid) - def get_user_oof_settings(opts) - opts = opts.clone - [:address].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetUserOofSettingsRequest { |x| - x.parent.default_namespace = @default_ns - builder.mailbox!(opts) + # -------------- Availability Operations ------------- + + # Gets a mailbox user's Out of Office (OOF) settings and messages. + # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx + # @param [Hash] opts + # @option opts [String] :address the email address of the user + # @option opts [String] :name the user display name (optional) + # @option opts [String] :routing_type the routing protocol (optional and stupid) + def get_user_oof_settings(opts) + opts = opts.clone + [:address].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserOofSettingsRequest { |x| + x.parent.default_namespace = @default_ns + builder.mailbox!(opts) + } + end } + do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - } - do_soap_request(req, response_class: EwsSoapAvailabilityResponse) - end - # Sets a mailbox user's Out of Office (OOF) settings and message. - # @see http://msdn.microsoft.com/en-us/library/aa580294.aspx - # @param [Hash] opts - # @option opts [Hash] :mailbox the mailbox hash for the use - # @option opts [String,Symbol] :oof_state :enabled, :disabled, :scheduled - # @option opts [Hash] :duration {start_time: DateTime, end_time: DateTime} - # @option opts [String] :internal_reply - # @option opts [String] :external_reply - # @option opts [String,Symbol] :external_audience :none, :known, :all - def set_user_oof_settings(opts) - opts = opts.clone - %i[mailbox oof_state].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.SetUserOofSettingsRequest { |x| - x.parent.default_namespace = @default_ns - builder.mailbox! opts.delete(:mailbox) - builder.user_oof_settings!(opts) + # Sets a mailbox user's Out of Office (OOF) settings and message. + # @see http://msdn.microsoft.com/en-us/library/aa580294.aspx + # @param [Hash] opts + # @option opts [Hash] :mailbox the mailbox hash for the use + # @option opts [String,Symbol] :oof_state :enabled, :disabled, :scheduled + # @option opts [Hash] :duration {start_time: DateTime, end_time: DateTime} + # @option opts [String] :internal_reply + # @option opts [String] :external_reply + # @option opts [String,Symbol] :external_audience :none, :known, :all + def set_user_oof_settings(opts) + opts = opts.clone + %i[mailbox oof_state].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.SetUserOofSettingsRequest { |x| + x.parent.default_namespace = @default_ns + builder.mailbox! opts.delete(:mailbox) + builder.user_oof_settings!(opts) + } + end } + do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - } - do_soap_request(req, response_class: EwsSoapAvailabilityResponse) + end end end end diff --git a/lib/ews/soap/exchange_data_services.rb b/lib/ews/soap/exchange_data_services.rb index a846183c..5ae7eb6e 100644 --- a/lib/ews/soap/exchange_data_services.rb +++ b/lib/ews/soap/exchange_data_services.rb @@ -1,757 +1,762 @@ # frozen_string_literal: true -module Viewpoint::EWS::SOAP - # Exchange Data Service operations as listed in the EWS Documentation. - # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx - module ExchangeDataServices - include Viewpoint::EWS::SOAP - - # -------------- Item Operations ------------- - - # Identifies items that are located in a specified folder - # @see http://msdn.microsoft.com/en-us/library/aa566107.aspx - # - # @param [Hash] opts - # @option opts [Array] :parent_folder_ids An Array of folder id Hashes, either a - # DistinguishedFolderId (must me a Symbol) or a FolderId (String) - # [{:id => , :change_key => }, {:id => :root}] - # @option opts [String] :traversal Shallow/Deep/SoftDeleted - # @option opts [Hash] :item_shape defines the ItemShape node - # @option item_shape [String] :base_shape IdOnly/Default/AllProperties - # @option item_shape :additional_properties - # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx - # @option opts [Hash] :calendar_view Limit FindItem by a start and end date - # {:calendar_view => {:max_entries_returned => 2, :start_date => - # , :end_date => }} - # @option opts [Hash] :contacts_view Limit FindItem between contact names - # {:contacts_view => {:max_entries_returned => 2, :initial_name => 'Dan', - # :final_name => 'Wally'}} - # @example - # { :parent_folder_ids => [{:id => root}], - # :traversal => 'Shallow', - # :item_shape => {:base_shape => 'Default'} } - def find_item(opts) - opts = opts.clone - %i[parent_folder_ids traversal item_shape].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.FindItem(Traversal: camel_case(opts[:traversal])) { - builder.nbuild.parent.default_namespace = @default_ns - builder.item_shape!(opts[:item_shape]) - builder.indexed_page_item_view!(opts[:indexed_page_item_view]) if opts[:indexed_page_item_view] - # @todo add FractionalPageFolderView - builder.calendar_view!(opts[:calendar_view]) if opts[:calendar_view] - builder.contacts_view!(opts[:contacts_view]) if opts[:contacts_view] - builder.restriction!(opts[:restriction]) if opts[:restriction] - builder.parent_folder_ids!(opts[:parent_folder_ids]) + +module Viewpoint + module EWS + module SOAP + # Exchange Data Service operations as listed in the EWS Documentation. + # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx + module ExchangeDataServices + include Viewpoint::EWS::SOAP + + # -------------- Item Operations ------------- + + # Identifies items that are located in a specified folder + # @see http://msdn.microsoft.com/en-us/library/aa566107.aspx + # + # @param [Hash] opts + # @option opts [Array] :parent_folder_ids An Array of folder id Hashes, either a + # DistinguishedFolderId (must me a Symbol) or a FolderId (String) + # [{:id => , :change_key => }, {:id => :root}] + # @option opts [String] :traversal Shallow/Deep/SoftDeleted + # @option opts [Hash] :item_shape defines the ItemShape node + # @option item_shape [String] :base_shape IdOnly/Default/AllProperties + # @option item_shape :additional_properties + # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx + # @option opts [Hash] :calendar_view Limit FindItem by a start and end date + # {:calendar_view => {:max_entries_returned => 2, :start_date => + # , :end_date => }} + # @option opts [Hash] :contacts_view Limit FindItem between contact names + # {:contacts_view => {:max_entries_returned => 2, :initial_name => 'Dan', + # :final_name => 'Wally'}} + # @example + # { :parent_folder_ids => [{:id => root}], + # :traversal => 'Shallow', + # :item_shape => {:base_shape => 'Default'} } + def find_item(opts) + opts = opts.clone + %i[parent_folder_ids traversal item_shape].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.FindItem(Traversal: camel_case(opts[:traversal])) { + builder.nbuild.parent.default_namespace = @default_ns + builder.item_shape!(opts[:item_shape]) + builder.indexed_page_item_view!(opts[:indexed_page_item_view]) if opts[:indexed_page_item_view] + # @todo add FractionalPageFolderView + builder.calendar_view!(opts[:calendar_view]) if opts[:calendar_view] + builder.contacts_view!(opts[:contacts_view]) if opts[:contacts_view] + builder.restriction!(opts[:restriction]) if opts[:restriction] + builder.parent_folder_ids!(opts[:parent_folder_ids]) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Gets items from the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa565934(v=EXCHG.140).aspx - # - # @param [Hash] opts - # @option opts [Hash] :item_shape The item shape properties - # Ex: {:base_shape => 'Default'} - # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be - # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the - # Microsoft docs for more information. - # @example - # opts = { - # :item_shape => {:base_shape => 'Default'}, - # :item_ids => [ - # {:item_id => {:id => 'id1'}}, - # {:occurrence_item_id => {:recurring_master_id => 'rid1', :change_key => 'ck', :instance_index => 1}}, - # {:recurring_master_item_id => {:occurrence_id => 'oid1', :change_key => 'ck'}} - # ]} - def get_item(opts) - opts = opts.clone - %i[item_shape item_ids].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetItem { - builder.nbuild.parent.default_namespace = @default_ns - builder.item_shape!(opts[:item_shape]) - builder.item_ids!(opts[:item_ids]) + # Gets items from the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa565934(v=EXCHG.140).aspx + # + # @param [Hash] opts + # @option opts [Hash] :item_shape The item shape properties + # Ex: {:base_shape => 'Default'} + # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be + # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the + # Microsoft docs for more information. + # @example + # opts = { + # :item_shape => {:base_shape => 'Default'}, + # :item_ids => [ + # {:item_id => {:id => 'id1'}}, + # {:occurrence_item_id => {:recurring_master_id => 'rid1', :change_key => 'ck', :instance_index => 1}}, + # {:recurring_master_item_id => {:occurrence_id => 'oid1', :change_key => 'ck'}} + # ]} + def get_item(opts) + opts = opts.clone + %i[item_shape item_ids].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetItem { + builder.nbuild.parent.default_namespace = @default_ns + builder.item_shape!(opts[:item_shape]) + builder.item_ids!(opts[:item_ids]) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Defines a request to create an item in the Exchange store. - # @see http://msdn.microsoft.com/en-us/library/aa565209(v=EXCHG.140).aspx - # - # @param [Hash] opts - # @option opts [String] :message_disposition How the item will be handled after it is created. - # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy' - # @option opts [String] :send_meeting_invitations How meeting requests are handled after they - # are created. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll', - # 'SendToAllAndSaveCopy' - # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} - # Will on work if 'SendOnly' is specified for :message_disposition - # @option opts [Array] :items This is a complex Hash that conforms to various Item types. - # Please see the Microsoft documentation for this element. - # @example - # opts = { - # message_disposition: 'SendAndSaveCopy', - # items: [ {message: - # {subject: 'test2', - # body: {body_type: 'Text', text: 'this is a test'}, - # to_recipients: [{mailbox: {email_address: 'dan.wanek@gmail.com'}}] - # } - # }]} - # - # opts = { - # send_meeting_invitations: 'SendToAllAndSaveCopy', - # items: [ {calendar_item: - # {subject: 'test cal item', - # body: {body_type: 'Text', text: 'this is a test cal item'}, - # start: {text: Chronic.parse('tomorrow at 4pm').to_datetime.to_s}, - # end: {text: Chronic.parse('tomorrow at 5pm').to_datetime.to_s}, - # required_attendees: [ - # {attendee: {mailbox: {email_address: 'dan.wanek@gmail.com'}}}, - # ] - # } - # }] - def create_item(opts) - opts = opts.clone - [:items].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - attribs = {} - attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] - attribs['SendMeetingInvitations'] = opts[:send_meeting_invitations] if opts[:send_meeting_invitations] - unless type == :header - builder.nbuild.CreateItem(attribs) { - builder.nbuild.parent.default_namespace = @default_ns - builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] - builder.nbuild.Items { - opts[:items].each { |i| - # The key can be any number of item types like :message, - # :calendar, etc - ikey = i.keys.first - builder.send("#{ikey}!", i[ikey]) + # Defines a request to create an item in the Exchange store. + # @see http://msdn.microsoft.com/en-us/library/aa565209(v=EXCHG.140).aspx + # + # @param [Hash] opts + # @option opts [String] :message_disposition How the item will be handled after it is created. + # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy' + # @option opts [String] :send_meeting_invitations How meeting requests are handled after they + # are created. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll', + # 'SendToAllAndSaveCopy' + # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} + # Will on work if 'SendOnly' is specified for :message_disposition + # @option opts [Array] :items This is a complex Hash that conforms to various Item types. + # Please see the Microsoft documentation for this element. + # @example + # opts = { + # message_disposition: 'SendAndSaveCopy', + # items: [ {message: + # {subject: 'test2', + # body: {body_type: 'Text', text: 'this is a test'}, + # to_recipients: [{mailbox: {email_address: 'dan.wanek@gmail.com'}}] + # } + # }]} + # + # opts = { + # send_meeting_invitations: 'SendToAllAndSaveCopy', + # items: [ {calendar_item: + # {subject: 'test cal item', + # body: {body_type: 'Text', text: 'this is a test cal item'}, + # start: {text: Chronic.parse('tomorrow at 4pm').to_datetime.to_s}, + # end: {text: Chronic.parse('tomorrow at 5pm').to_datetime.to_s}, + # required_attendees: [ + # {attendee: {mailbox: {email_address: 'dan.wanek@gmail.com'}}}, + # ] + # } + # }] + def create_item(opts) + opts = opts.clone + [:items].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + attribs = {} + attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] + attribs['SendMeetingInvitations'] = opts[:send_meeting_invitations] if opts[:send_meeting_invitations] + unless type == :header + builder.nbuild.CreateItem(attribs) { + builder.nbuild.parent.default_namespace = @default_ns + builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] + builder.nbuild.Items { + opts[:items].each { |i| + # The key can be any number of item types like :message, + # :calendar, etc + ikey = i.keys.first + builder.send("#{ikey}!", i[ikey]) + } + } } - } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Used to modify the properties of an existing item in the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa581084(v=exchg.140).aspx - # - # @param [Hash] opts - # @option opts [String] :conflict_resolution Identifies the type of conflict resolution to - # try during an update. The default value is AutoResolve. Available options are - # 'NeverOverwrite', 'AutoResolve', 'AlwaysOverwrite' - # @option opts [String] :message_disposition How the item will be handled after it is updated. - # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy' - # @option opts [String] :send_meeting_invitations_or_cancellations How meeting requests are - # handled after they are updated. Required for calendar items. Must be one of 'SendToNone', - # 'SendOnlyToAll', 'SendOnlyToChanged', 'SendToAllAndSaveCopy', 'SendToChangedAndSaveCopy' - # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems} - # Will on work if 'SendOnly' is specified for :message_disposition - # @option opts [Array] :item_changes an array of ItemChange elements that identify items - # and the updates to apply to the items. See the Microsoft docs for more information. - # @example - # opts = { - # :send_meeting_invitations_or_cancellations => 'SendOnlyToChangedAndSaveCopy', - # :item_changes => [ - # { :item_id => {:id => 'id1'}, - # :updates => [ - # {:set_item_field => { - # :field_uRI => {:field_uRI => 'item:Subject'}, - # # The following needs to conform to #build_xml! format for now - # :calendar_item => { :sub_elements => [{:subject => {:text => 'Test Subject'}}]} - # }} - # ] - # } - # ] - # } - def update_item(opts) - opts = opts.clone - [:item_changes].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - attribs = {} - attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] - attribs['ConflictResolution'] = opts[:conflict_resolution] if opts[:conflict_resolution] - if opts[:send_meeting_invitations_or_cancellations] - attribs['SendMeetingInvitationsOrCancellations'] = - opts[:send_meeting_invitations_or_cancellations] - end - unless type == :header - builder.nbuild.UpdateItem(attribs) { - builder.nbuild.parent.default_namespace = @default_ns - builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] - builder.item_changes!(opts[:item_changes]) + # Used to modify the properties of an existing item in the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa581084(v=exchg.140).aspx + # + # @param [Hash] opts + # @option opts [String] :conflict_resolution Identifies the type of conflict resolution to + # try during an update. The default value is AutoResolve. Available options are + # 'NeverOverwrite', 'AutoResolve', 'AlwaysOverwrite' + # @option opts [String] :message_disposition How the item will be handled after it is updated. + # Only applicable for to e-mail. Must be one of 'SaveOnly', 'SendOnly', or 'SendAndSaveCopy' + # @option opts [String] :send_meeting_invitations_or_cancellations How meeting requests are + # handled after they are updated. Required for calendar items. Must be one of 'SendToNone', + # 'SendOnlyToAll', 'SendOnlyToChanged', 'SendToAllAndSaveCopy', 'SendToChangedAndSaveCopy' + # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems} + # Will on work if 'SendOnly' is specified for :message_disposition + # @option opts [Array] :item_changes an array of ItemChange elements that identify items + # and the updates to apply to the items. See the Microsoft docs for more information. + # @example + # opts = { + # :send_meeting_invitations_or_cancellations => 'SendOnlyToChangedAndSaveCopy', + # :item_changes => [ + # { :item_id => {:id => 'id1'}, + # :updates => [ + # {:set_item_field => { + # :field_uRI => {:field_uRI => 'item:Subject'}, + # # The following needs to conform to #build_xml! format for now + # :calendar_item => { :sub_elements => [{:subject => {:text => 'Test Subject'}}]} + # }} + # ] + # } + # ] + # } + def update_item(opts) + opts = opts.clone + [:item_changes].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + attribs = {} + attribs['MessageDisposition'] = opts[:message_disposition] if opts[:message_disposition] + attribs['ConflictResolution'] = opts[:conflict_resolution] if opts[:conflict_resolution] + if opts[:send_meeting_invitations_or_cancellations] + attribs['SendMeetingInvitationsOrCancellations'] = + opts[:send_meeting_invitations_or_cancellations] + end + unless type == :header + builder.nbuild.UpdateItem(attribs) { + builder.nbuild.parent.default_namespace = @default_ns + builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] + builder.item_changes!(opts[:item_changes]) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Delete an item from a mailbox in the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa580484(v=exchg.140).aspx - # - # @param [Hash] opts - # @option opts [String] :delete_type Describes how an item is deleted. Must be one of - # 'HardDelete', 'SoftDelete', or 'MoveToDeletedItems' - # @option opts [String] :send_meeting_cancellations How meetings are handled after they - # are deleted. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll', - # 'SendToAllAndSaveCopy' - # @option opts [String] :affected_task_occurrences Describes whether a task instance or a - # task master is deleted by a DeleteItem Operation. This attribute is required when - # tasks are deleted. Must be one of 'AllOccurrences' or 'SpecifiedOccurrenceOnly' - # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be - # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the - # Microsoft docs for more information. - # @example - # opts = { - # :delete_type => 'MoveToDeletedItems', - # :item_ids => [{:item_id => {:id => 'id1'}}] - # } - # inst.delete_item(opts) - def delete_item(opts) - opts = opts.clone - %i[delete_type item_ids].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - attribs = { 'DeleteType' => opts[:delete_type] } - attribs['SendMeetingCancellations'] = opts[:send_meeting_cancellations] if opts[:send_meeting_cancellations] - attribs['AffectedTaskOccurrences'] = opts[:affected_task_occurrences] if opts[:affected_task_occurrences] - unless type == :header - builder.nbuild.DeleteItem(attribs) { - builder.nbuild.parent.default_namespace = @default_ns - builder.item_ids!(opts[:item_ids]) + # Delete an item from a mailbox in the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa580484(v=exchg.140).aspx + # + # @param [Hash] opts + # @option opts [String] :delete_type Describes how an item is deleted. Must be one of + # 'HardDelete', 'SoftDelete', or 'MoveToDeletedItems' + # @option opts [String] :send_meeting_cancellations How meetings are handled after they + # are deleted. Required for calendar items. Must be one of 'SendToNone', 'SendOnlyToAll', + # 'SendToAllAndSaveCopy' + # @option opts [String] :affected_task_occurrences Describes whether a task instance or a + # task master is deleted by a DeleteItem Operation. This attribute is required when + # tasks are deleted. Must be one of 'AllOccurrences' or 'SpecifiedOccurrenceOnly' + # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be + # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the + # Microsoft docs for more information. + # @example + # opts = { + # :delete_type => 'MoveToDeletedItems', + # :item_ids => [{:item_id => {:id => 'id1'}}] + # } + # inst.delete_item(opts) + def delete_item(opts) + opts = opts.clone + %i[delete_type item_ids].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + attribs = { 'DeleteType' => opts[:delete_type] } + attribs['SendMeetingCancellations'] = opts[:send_meeting_cancellations] if opts[:send_meeting_cancellations] + attribs['AffectedTaskOccurrences'] = opts[:affected_task_occurrences] if opts[:affected_task_occurrences] + unless type == :header + builder.nbuild.DeleteItem(attribs) { + builder.nbuild.parent.default_namespace = @default_ns + builder.item_ids!(opts[:item_ids]) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Used to move one or more items to a single destination folder. - # @see http://msdn.microsoft.com/en-us/library/aa565781(v=exchg.140).aspx - # - # @param [Hash] opts - # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} - # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be - # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the - # Microsoft docs for more information. - # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of - # new items are returned in the response - # @example - # opts = { - # :to_folder_id => {:id => :inbox}, - # :item_ids => [ - # {:item_id => {:id => 'id1'}}, - # {:item_id => {:id => 'id2'}}, - # ], - # :return_new_item_ids => true - # } - # obj.move_item(opts) - def move_item(opts) - opts = opts.clone - %i[to_folder_id item_ids].each do |k| - validate_param(opts, k, true) - end - return_new_ids = validate_param(opts, :return_new_item_ids, false, true) - - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.MoveItem { - builder.nbuild.parent.default_namespace = @default_ns - builder.to_folder_id!(opts[:to_folder_id]) - builder.item_ids!(opts[:item_ids]) - builder.return_new_item_ids!(return_new_ids) + # Used to move one or more items to a single destination folder. + # @see http://msdn.microsoft.com/en-us/library/aa565781(v=exchg.140).aspx + # + # @param [Hash] opts + # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} + # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be + # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the + # Microsoft docs for more information. + # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of + # new items are returned in the response + # @example + # opts = { + # :to_folder_id => {:id => :inbox}, + # :item_ids => [ + # {:item_id => {:id => 'id1'}}, + # {:item_id => {:id => 'id2'}}, + # ], + # :return_new_item_ids => true + # } + # obj.move_item(opts) + def move_item(opts) + opts = opts.clone + %i[to_folder_id item_ids].each do |k| + validate_param(opts, k, true) + end + return_new_ids = validate_param(opts, :return_new_item_ids, false, true) + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.MoveItem { + builder.nbuild.parent.default_namespace = @default_ns + builder.to_folder_id!(opts[:to_folder_id]) + builder.item_ids!(opts[:item_ids]) + builder.return_new_item_ids!(return_new_ids) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Copies items and puts the items in a different folder - # @see http://msdn.microsoft.com/en-us/library/aa565012(v=exchg.140).aspx - # - # @param [Hash] opts - # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} - # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be - # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the - # Microsoft docs for more information. - # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of - # new items are returned in the response - # @example - # opts = { - # :to_folder_id => {:id => :inbox}, - # :item_ids => [ - # {:item_id => {:id => 'id1'}}, - # {:item_id => {:id => 'id2'}}, - # ], - # :return_new_item_ids => true - # } - # obj.copy_item(opts) - def copy_item(opts) - opts = opts.clone - %i[to_folder_id item_ids].each do |k| - validate_param(opts, k, true) - end - return_new_ids = validate_param(opts, :return_new_item_ids, false, true) - - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.CopyItem { - builder.nbuild.parent.default_namespace = @default_ns - builder.to_folder_id!(opts[:to_folder_id]) - builder.item_ids!(opts[:item_ids]) - builder.return_new_item_ids!(return_new_ids) + # Copies items and puts the items in a different folder + # @see http://msdn.microsoft.com/en-us/library/aa565012(v=exchg.140).aspx + # + # @param [Hash] opts + # @option opts [Hash] :to_folder_id A well formatted folder_id Hash. Ex: {:id => :inbox} + # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be + # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the + # Microsoft docs for more information. + # @option opts [Boolean] :return_new_item_ids Indicates whether the item identifiers of + # new items are returned in the response + # @example + # opts = { + # :to_folder_id => {:id => :inbox}, + # :item_ids => [ + # {:item_id => {:id => 'id1'}}, + # {:item_id => {:id => 'id2'}}, + # ], + # :return_new_item_ids => true + # } + # obj.copy_item(opts) + def copy_item(opts) + opts = opts.clone + %i[to_folder_id item_ids].each do |k| + validate_param(opts, k, true) + end + return_new_ids = validate_param(opts, :return_new_item_ids, false, true) + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CopyItem { + builder.nbuild.parent.default_namespace = @default_ns + builder.to_folder_id!(opts[:to_folder_id]) + builder.item_ids!(opts[:item_ids]) + builder.return_new_item_ids!(return_new_ids) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - - # Used to send e-mail messages that are located in the Exchange store. - # @see http://msdn.microsoft.com/en-us/library/aa580238(v=exchg.140).aspx - # - # @param [Hash] opts - # @option opts [Boolean] :save_item_to_folder To save or not to save... save! :-) - # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems} - # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be - # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the - # Microsoft docs for more information. - # @example - # opts = { - # :save_item_to_folder => true, - # :saved_item_folder_id => {:id => :sentitems}, - # :item_ids => [ - # {:item_id => {:id => 'id1'}}, - # {:item_id => {:id => 'id2'}}, - # ]} - # obj.send_item(opts) - def send_item(opts) - opts = opts.clone - [:item_ids].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - attribs = {} - attribs['SaveItemToFolder'] = validate_param(opts, :save_item_to_folder, false, true) - unless type == :header - builder.nbuild.SendItem(attribs) { - builder.nbuild.parent.default_namespace = @default_ns - builder.item_ids!(opts[:item_ids]) - builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] + # Used to send e-mail messages that are located in the Exchange store. + # @see http://msdn.microsoft.com/en-us/library/aa580238(v=exchg.140).aspx + # + # @param [Hash] opts + # @option opts [Boolean] :save_item_to_folder To save or not to save... save! :-) + # @option opts [Hash] :saved_item_folder_id A well formatted folder_id Hash. Ex: {:id => :sentitems} + # @option opts [Array] :item_ids ItemIds Hash. The keys in these Hashes can be + # :item_id, :occurrence_item_id, or :recurring_master_item_id. Please see the + # Microsoft docs for more information. + # @example + # opts = { + # :save_item_to_folder => true, + # :saved_item_folder_id => {:id => :sentitems}, + # :item_ids => [ + # {:item_id => {:id => 'id1'}}, + # {:item_id => {:id => 'id2'}}, + # ]} + # obj.send_item(opts) + def send_item(opts) + opts = opts.clone + [:item_ids].each do |k| + validate_param(opts, k, true) + end + + req = build_soap! { |type, builder| + attribs = {} + attribs['SaveItemToFolder'] = validate_param(opts, :save_item_to_folder, false, true) + unless type == :header + builder.nbuild.SendItem(attribs) { + builder.nbuild.parent.default_namespace = @default_ns + builder.item_ids!(opts[:item_ids]) + builder.saved_item_folder_id!(opts[:saved_item_folder_id]) if opts[:saved_item_folder_id] + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Export items as a base64 string - # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx - # - # (Requires Exchange version equal or newer than VERSION 2010 SP 1) - # - # @param ids [Array] array of item ids. Can also be a single id value - def export_items(ids) - validate_version(VERSION_2010_SP1) - ids = ids.clone - [:item_ids].each do |k| - validate_param(ids, k, true) - end - req = build_soap! { |type, builder| - builder.export_item_ids!(ids[:item_ids]) unless type == :header - } - do_soap_request(req, response_class: EwsResponse) - end - - # ------------- Folder Operations ------------ - - # Creates folders, calendar folders, contacts folders, tasks folders, and search folders. - # @see http://msdn.microsoft.com/en-us/library/aa563574.aspx CreateFolder - # - # @param [Hash] opts - # @option opts [Hash] :parent_folder_id A hash with either the name of a - # folder or it's numerical ID. - # See: http://msdn.microsoft.com/en-us/library/aa565998.aspx - # {:id => :root} or {:id => 'myfolderid#'} - # @option opts [Array] :folders An array of hashes of folder types - # that conform to input for build_xml! - # @example [ - # {:folder => - # {:display_name => "New Folder"}}, - # {:calendar_folder => - # {:folder_id => {:id => 'blah', :change_key => 'blah'}}} - def create_folder(opts) - opts = opts.clone - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.CreateFolder { |x| - x.parent.default_namespace = @default_ns - builder.parent_folder_id!(opts[:parent_folder_id]) - builder.folders!(opts[:folders]) + # Export items as a base64 string + # @see http://msdn.microsoft.com/en-us/library/ff709503(v=exchg.140).aspx + # + # (Requires Exchange version equal or newer than VERSION 2010 SP 1) + # + # @param ids [Array] array of item ids. Can also be a single id value + def export_items(ids) + validate_version(VERSION_2010_SP1) + ids = ids.clone + [:item_ids].each do |k| + validate_param(ids, k, true) + end + req = build_soap! { |type, builder| + builder.export_item_ids!(ids[:item_ids]) unless type == :header } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req) - end - # Defines a request to copy folders in the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa563949.aspx - # @param [Hash] to_folder_id The target FolderId - # {:id => , :change_key => } - # @param [Array] *sources The source Folders - # {:id => , :change_key => }, - # {:id => , :change_key => } - def copy_folder(to_folder_id, *sources) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.CopyFolder { - builder.nbuild.parent.default_namespace = @default_ns - builder.to_folder_id!(to_folder_id) - builder.folder_ids!(sources.flatten) + # ------------- Folder Operations ------------ + + # Creates folders, calendar folders, contacts folders, tasks folders, and search folders. + # @see http://msdn.microsoft.com/en-us/library/aa563574.aspx CreateFolder + # + # @param [Hash] opts + # @option opts [Hash] :parent_folder_id A hash with either the name of a + # folder or it's numerical ID. + # See: http://msdn.microsoft.com/en-us/library/aa565998.aspx + # {:id => :root} or {:id => 'myfolderid#'} + # @option opts [Array] :folders An array of hashes of folder types + # that conform to input for build_xml! + # @example [ + # {:folder => + # {:display_name => "New Folder"}}, + # {:calendar_folder => + # {:folder_id => {:id => 'blah', :change_key => 'blah'}}} + def create_folder(opts) + opts = opts.clone + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CreateFolder { |x| + x.parent.default_namespace = @default_ns + builder.parent_folder_id!(opts[:parent_folder_id]) + builder.folders!(opts[:folders]) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Deletes folders from a mailbox. - # @see http://msdn.microsoft.com/en-us/library/aa564767.aspx DeleteFolder - # - # @param [Hash] opts - # @option opts [Array] :folder_ids An array of folder_ids in the form: - # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, - # {:id => :msgfolderroot} ] # Don't do this for real - # @option opts [String,nil] :delete_type Type of delete to do: - # HardDelete/SoftDelete/MoveToDeletedItems - # @option opts [String,nil] :act_as User to act on behalf as. This user - # must have been given delegate access to this folder or else this - # operation will fail. - def delete_folder(opts) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.DeleteFolder('DeleteType' => opts[:delete_type]) { - builder.nbuild.parent.default_namespace = @default_ns - builder.folder_ids!(opts[:folder_ids], opts[:act_as]) + # Defines a request to copy folders in the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa563949.aspx + # @param [Hash] to_folder_id The target FolderId + # {:id => , :change_key => } + # @param [Array] *sources The source Folders + # {:id => , :change_key => }, + # {:id => , :change_key => } + def copy_folder(to_folder_id, *sources) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CopyFolder { + builder.nbuild.parent.default_namespace = @default_ns + builder.to_folder_id!(to_folder_id) + builder.folder_ids!(sources.flatten) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Find subfolders of an identified folder - # @see http://msdn.microsoft.com/en-us/library/aa563918.aspx - # - # @param [Hash] opts - # @option opts [Array] :parent_folder_ids An Array of folder id Hashes, - # either a DistinguishedFolderId (must me a Symbol) or a FolderId (String) - # [{:id => , :change_key => }, {:id => :root}] - # @option opts [String] :traversal Shallow/Deep/SoftDeleted - # @option opts [Hash] :folder_shape defines the FolderShape node - # See: http://msdn.microsoft.com/en-us/library/aa494311.aspx - # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties - # @option folder_shape :additional_properties - # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx - # @option opts [Hash] :restriction A well formatted restriction Hash. - # @example - # { :parent_folder_ids => [{:id => root}], - # :traversal => 'Deep', - # :folder_shape => {:base_shape => 'Default'} } - # @todo add FractionalPageFolderView - def find_folder(opts) - opts = opts.clone - %i[parent_folder_ids traversal folder_shape].each do |k| - validate_param(opts, k, true) - end + # Deletes folders from a mailbox. + # @see http://msdn.microsoft.com/en-us/library/aa564767.aspx DeleteFolder + # + # @param [Hash] opts + # @option opts [Array] :folder_ids An array of folder_ids in the form: + # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, + # {:id => :msgfolderroot} ] # Don't do this for real + # @option opts [String,nil] :delete_type Type of delete to do: + # HardDelete/SoftDelete/MoveToDeletedItems + # @option opts [String,nil] :act_as User to act on behalf as. This user + # must have been given delegate access to this folder or else this + # operation will fail. + def delete_folder(opts) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.DeleteFolder('DeleteType' => opts[:delete_type]) { + builder.nbuild.parent.default_namespace = @default_ns + builder.folder_ids!(opts[:folder_ids], opts[:act_as]) + } + end + } + do_soap_request(req) + end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.FindFolder(Traversal: camel_case(opts[:traversal])) { - builder.nbuild.parent.default_namespace = @default_ns - builder.folder_shape!(opts[:folder_shape]) - builder.restriction!(opts[:restriction]) if opts[:restriction] - builder.parent_folder_ids!(opts[:parent_folder_ids]) + # Find subfolders of an identified folder + # @see http://msdn.microsoft.com/en-us/library/aa563918.aspx + # + # @param [Hash] opts + # @option opts [Array] :parent_folder_ids An Array of folder id Hashes, + # either a DistinguishedFolderId (must me a Symbol) or a FolderId (String) + # [{:id => , :change_key => }, {:id => :root}] + # @option opts [String] :traversal Shallow/Deep/SoftDeleted + # @option opts [Hash] :folder_shape defines the FolderShape node + # See: http://msdn.microsoft.com/en-us/library/aa494311.aspx + # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties + # @option folder_shape :additional_properties + # See: http://msdn.microsoft.com/en-us/library/aa563810.aspx + # @option opts [Hash] :restriction A well formatted restriction Hash. + # @example + # { :parent_folder_ids => [{:id => root}], + # :traversal => 'Deep', + # :folder_shape => {:base_shape => 'Default'} } + # @todo add FractionalPageFolderView + def find_folder(opts) + opts = opts.clone + %i[parent_folder_ids traversal folder_shape].each do |k| + validate_param(opts, k, true) + end + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.FindFolder(Traversal: camel_case(opts[:traversal])) { + builder.nbuild.parent.default_namespace = @default_ns + builder.folder_shape!(opts[:folder_shape]) + builder.restriction!(opts[:restriction]) if opts[:restriction] + builder.parent_folder_ids!(opts[:parent_folder_ids]) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Gets folders from the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa580274.aspx - # - # @param [Hash] opts - # @option opts [Array] :folder_ids An array of folder_ids in the form: - # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, - # {:id => :msgfolderroot} ] - # @option opts [Hash] :folder_shape defines the FolderShape node - # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties - # @option folder_shape :additional_properties - # @option opts [String,nil] :act_as User to act on behalf as. This user must - # have been given delegate access to this folder or else this operation - # will fail. - # @example - # { :folder_ids => [{:id => :msgfolderroot}], - # :folder_shape => {:base_shape => 'Default'} } - def get_folder(opts) - opts = opts.clone - %i[folder_ids folder_shape].each do |k| - validate_param(opts, k, true) - end - validate_param(opts[:folder_shape], :base_shape, true) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetFolder { - builder.nbuild.parent.default_namespace = @default_ns - builder.folder_shape!(opts[:folder_shape]) - builder.folder_ids!(opts[:folder_ids], opts[:act_as]) + # Gets folders from the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa580274.aspx + # + # @param [Hash] opts + # @option opts [Array] :folder_ids An array of folder_ids in the form: + # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, + # {:id => :msgfolderroot} ] + # @option opts [Hash] :folder_shape defines the FolderShape node + # @option folder_shape [String] :base_shape IdOnly/Default/AllProperties + # @option folder_shape :additional_properties + # @option opts [String,nil] :act_as User to act on behalf as. This user must + # have been given delegate access to this folder or else this operation + # will fail. + # @example + # { :folder_ids => [{:id => :msgfolderroot}], + # :folder_shape => {:base_shape => 'Default'} } + def get_folder(opts) + opts = opts.clone + %i[folder_ids folder_shape].each do |k| + validate_param(opts, k, true) + end + validate_param(opts[:folder_shape], :base_shape, true) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetFolder { + builder.nbuild.parent.default_namespace = @default_ns + builder.folder_shape!(opts[:folder_shape]) + builder.folder_ids!(opts[:folder_ids], opts[:act_as]) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Defines a request to move folders in the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa566202.aspx - # @param [Hash] to_folder_id The target FolderId - # {:id => , :change_key => } - # @param [Array] *sources The source Folders - # {:id => , :change_key => }, - # {:id => , :change_key => } - def move_folder(to_folder_id, *sources) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.MoveFolder { - builder.nbuild.parent.default_namespace = @default_ns - builder.to_folder_id!(to_folder_id) - builder.folder_ids!(sources.flatten) + # Defines a request to move folders in the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa566202.aspx + # @param [Hash] to_folder_id The target FolderId + # {:id => , :change_key => } + # @param [Array] *sources The source Folders + # {:id => , :change_key => }, + # {:id => , :change_key => } + def move_folder(to_folder_id, *sources) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.MoveFolder { + builder.nbuild.parent.default_namespace = @default_ns + builder.to_folder_id!(to_folder_id) + builder.folder_ids!(sources.flatten) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Update properties for a specified folder - # There is a lot more building in this method because most of the builders - # are only used for this operation so there was no need to externalize them - # for re-use. - # @see http://msdn.microsoft.com/en-us/library/aa580519(v=EXCHG.140).aspx - # @param [Array] folder_changes an Array of well formatted Hashes - def update_folder(folder_changes) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.UpdateFolder { - builder.nbuild.parent.default_namespace = @default_ns - builder.nbuild.FolderChanges { - folder_changes.each do |fc| - builder[NS_EWS_TYPES].FolderChange { - builder.dispatch_folder_id!(fc) - builder[NS_EWS_TYPES].Updates { - # @todo finish implementation - } + # Update properties for a specified folder + # There is a lot more building in this method because most of the builders + # are only used for this operation so there was no need to externalize them + # for re-use. + # @see http://msdn.microsoft.com/en-us/library/aa580519(v=EXCHG.140).aspx + # @param [Array] folder_changes an Array of well formatted Hashes + def update_folder(folder_changes) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.UpdateFolder { + builder.nbuild.parent.default_namespace = @default_ns + builder.nbuild.FolderChanges { + folder_changes.each do |fc| + builder[NS_EWS_TYPES].FolderChange { + builder.dispatch_folder_id!(fc) + builder[NS_EWS_TYPES].Updates { + # @todo finish implementation + } + } + end } - end - } + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Empties folders in a mailbox. - # @see http://msdn.microsoft.com/en-us/library/ff709484.aspx - # @param [Hash] opts - # @option opts [String] :delete_type Must be one of - # ExchangeDataServices::HARD_DELETE, SOFT_DELETE, or MOVE_TO_DELETED_ITEMS - # @option opts [Boolean] :delete_sub_folders - # @option opts [Array] :folder_ids An array of folder_ids in the form: - # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, - # {:id => 'blah'} ] - # @todo Finish - def empty_folder(opts) - validate_version(VERSION_2010_SP1) - ef_opts = {} - %i[delete_type delete_sub_folders].each do |k| - ef_opts[camel_case(k)] = validate_param(opts, k, true) - end - fids = validate_param opts, :folder_ids, true - - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.EmptyFolder(ef_opts) { |_x| - builder.nbuild.parent.default_namespace = @default_ns - builder.folder_ids!(fids) + # Empties folders in a mailbox. + # @see http://msdn.microsoft.com/en-us/library/ff709484.aspx + # @param [Hash] opts + # @option opts [String] :delete_type Must be one of + # ExchangeDataServices::HARD_DELETE, SOFT_DELETE, or MOVE_TO_DELETED_ITEMS + # @option opts [Boolean] :delete_sub_folders + # @option opts [Array] :folder_ids An array of folder_ids in the form: + # [ {:id => 'myfolderID##asdfs', :change_key => 'asdfasdf'}, + # {:id => 'blah'} ] + # @todo Finish + def empty_folder(opts) + validate_version(VERSION_2010_SP1) + ef_opts = {} + %i[delete_type delete_sub_folders].each do |k| + ef_opts[camel_case(k)] = validate_param(opts, k, true) + end + fids = validate_param opts, :folder_ids, true + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.EmptyFolder(ef_opts) { |_x| + builder.nbuild.parent.default_namespace = @default_ns + builder.folder_ids!(fids) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # ----------- Attachment Operations ---------- - - # Used to retrieve existing attachments on items in the Exchange store - # @see http://msdn.microsoft.com/en-us/library/aa494316.aspx - # @param [Hash] opts - # @option opts [Array] :attachment_ids Attachment Ids to fetch - # @option opts [Hash] :attachment_shape Attachment shape - # include_mime_content: true or false (optional) - # body_type: "Best" | "HTML" | "Text" (optional) - # filter_html_content: true or false (optional) - # additional_properties: @todo finish implementation - def get_attachment(opts) - opts = opts.clone - [:attachment_ids].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetAttachment { |_x| - builder.nbuild.parent.default_namespace = @default_ns - builder.attachment_ids!(opts[:attachment_ids]) + # ----------- Attachment Operations ---------- + + # Used to retrieve existing attachments on items in the Exchange store + # @see http://msdn.microsoft.com/en-us/library/aa494316.aspx + # @param [Hash] opts + # @option opts [Array] :attachment_ids Attachment Ids to fetch + # @option opts [Hash] :attachment_shape Attachment shape + # include_mime_content: true or false (optional) + # body_type: "Best" | "HTML" | "Text" (optional) + # filter_html_content: true or false (optional) + # additional_properties: @todo finish implementation + def get_attachment(opts) + opts = opts.clone + [:attachment_ids].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetAttachment { |_x| + builder.nbuild.parent.default_namespace = @default_ns + builder.attachment_ids!(opts[:attachment_ids]) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Creates either an item or file attachment and attaches it to the specified item. - # @see http://msdn.microsoft.com/en-us/library/aa565877.aspx - # @param [Hash] opts - # @option opts [Hash] :parent_id {id: , change_key: } - # @option opts [Array] :files An Array of Base64 encoded Strings with - # an associated name: - # {:name => , :content => } - # @option opts [Array] :items Exchange Items to attach to this Item - # @todo Need to implement attachment of Item types - def create_attachment(opts) - opts = opts.clone - [:parent_id].each do |k| - validate_param(opts, k, true) - end - validate_param(opts, :files, false, []) - validate_param(opts, :items, false, []) - - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.CreateAttachment { |x| - builder.nbuild.parent.default_namespace = @default_ns - builder.parent_item_id!(opts[:parent_id]) - x.Attachments { - opts[:files].each do |fa| - builder.file_attachment!(fa) - end - opts[:items].each do |ia| - builder.item_attachment!(ia) - end - opts[:inline_files].each do |fi| - builder.inline_attachment!(fi) - end - } + # Creates either an item or file attachment and attaches it to the specified item. + # @see http://msdn.microsoft.com/en-us/library/aa565877.aspx + # @param [Hash] opts + # @option opts [Hash] :parent_id {id: , change_key: } + # @option opts [Array] :files An Array of Base64 encoded Strings with + # an associated name: + # {:name => , :content => } + # @option opts [Array] :items Exchange Items to attach to this Item + # @todo Need to implement attachment of Item types + def create_attachment(opts) + opts = opts.clone + [:parent_id].each do |k| + validate_param(opts, k, true) + end + validate_param(opts, :files, false, []) + validate_param(opts, :items, false, []) + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.CreateAttachment { |x| + builder.nbuild.parent.default_namespace = @default_ns + builder.parent_item_id!(opts[:parent_id]) + x.Attachments { + opts[:files].each do |fa| + builder.file_attachment!(fa) + end + opts[:items].each do |ia| + builder.item_attachment!(ia) + end + opts[:inline_files].each do |fi| + builder.inline_attachment!(fi) + end + } + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # ------------ Utility Operations ------------ - - # Exposes the full membership of distribution lists. - # @see http://msdn.microsoft.com/en-us/library/aa494152.aspx ExpandDL - # - # @todo Fully support all of the ExpandDL operations. Today it just supports - # taking an e-mail address as an argument - # @param [Hash] opts - # @option opts [String] :email_address The e-mail address of the - # distribution to resolve - # @option opts [Hash] :item_id The ItemId of the private distribution to resolve. - # {:id => 'my id'} - def expand_dl(opts) - opts = opts.clone - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.ExpandDL { |x| - x.parent.default_namespace = @default_ns - x.Mailbox { |mb| - key = :email_address - mb[NS_EWS_TYPES].EmailAddress(opts[key]) if opts[key] - builder.item_id! if opts[:item_id] - } + # ------------ Utility Operations ------------ + + # Exposes the full membership of distribution lists. + # @see http://msdn.microsoft.com/en-us/library/aa494152.aspx ExpandDL + # + # @todo Fully support all of the ExpandDL operations. Today it just supports + # taking an e-mail address as an argument + # @param [Hash] opts + # @option opts [String] :email_address The e-mail address of the + # distribution to resolve + # @option opts [Hash] :item_id The ItemId of the private distribution to resolve. + # {:id => 'my id'} + def expand_dl(opts) + opts = opts.clone + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ExpandDL { |x| + x.parent.default_namespace = @default_ns + x.Mailbox { |mb| + key = :email_address + mb[NS_EWS_TYPES].EmailAddress(opts[key]) if opts[key] + builder.item_id! if opts[:item_id] + } + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Resolve ambiguous e-mail addresses and display names - # @see http://msdn.microsoft.com/en-us/library/aa565329.aspx ResolveNames - # @see http://msdn.microsoft.com/en-us/library/aa581054.aspx UnresolvedEntry - # @param [Hash] opts - # @option opts [String] :name the unresolved entry - # @option opts [Boolean] :full_contact_data (true) Whether or not to return - # the full contact details. - # @option opts [String] :search_scope where to seach for this entry, one of - # SOAP::Contacts, SOAP::ActiveDirectory, SOAP::ActiveDirectoryContacts - # (default), SOAP::ContactsActiveDirectory - # @option opts [String, FolderId] :parent_folder_id either the name of a - # folder or it's numerical ID. - # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx - def resolve_names(opts) - opts = opts.clone - fcd = opts.has_key?(:full_contact_data) ? opts[:full_contact_data] : true - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.ResolveNames { |x| - x.parent['ReturnFullContactData'] = fcd.to_s - x.parent['SearchScope'] = opts[:search_scope] if opts[:search_scope] - x.parent.default_namespace = @default_ns - # @todo builder.nbuild.ParentFolderIds - x.UnresolvedEntry(opts[:name]) + # Resolve ambiguous e-mail addresses and display names + # @see http://msdn.microsoft.com/en-us/library/aa565329.aspx ResolveNames + # @see http://msdn.microsoft.com/en-us/library/aa581054.aspx UnresolvedEntry + # @param [Hash] opts + # @option opts [String] :name the unresolved entry + # @option opts [Boolean] :full_contact_data (true) Whether or not to return + # the full contact details. + # @option opts [String] :search_scope where to seach for this entry, one of + # SOAP::Contacts, SOAP::ActiveDirectory, SOAP::ActiveDirectoryContacts + # (default), SOAP::ContactsActiveDirectory + # @option opts [String, FolderId] :parent_folder_id either the name of a + # folder or it's numerical ID. + # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx + def resolve_names(opts) + opts = opts.clone + fcd = opts.has_key?(:full_contact_data) ? opts[:full_contact_data] : true + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ResolveNames { |x| + x.parent['ReturnFullContactData'] = fcd.to_s + x.parent['SearchScope'] = opts[:search_scope] if opts[:search_scope] + x.parent.default_namespace = @default_ns + # @todo builder.nbuild.ParentFolderIds + x.UnresolvedEntry(opts[:name]) + } + end } + do_soap_request(req) end - } - do_soap_request(req) - end - # Converts item and folder identifiers between formats. - # @see http://msdn.microsoft.com/en-us/library/bb799665.aspx - # @todo Needs to be finished - def convert_id(opts) - opts = opts.clone - - %i[id format destination_format mailbox].each do |k| - validate_param(opts, k, true) - end - - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.ConvertId { |x| - builder.nbuild.parent.default_namespace = @default_ns - x.parent['DestinationFormat'] = opts[:destination_format].to_s.camel_case - x.SourceIds { |x| - x[NS_EWS_TYPES].AlternateId { |x| - x.parent['Format'] = opts[:format].to_s.camel_case - x.parent['Id'] = opts[:id] - x.parent['Mailbox'] = opts[:mailbox] + # Converts item and folder identifiers between formats. + # @see http://msdn.microsoft.com/en-us/library/bb799665.aspx + # @todo Needs to be finished + def convert_id(opts) + opts = opts.clone + + %i[id format destination_format mailbox].each do |k| + validate_param(opts, k, true) + end + + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.ConvertId { |x| + builder.nbuild.parent.default_namespace = @default_ns + x.parent['DestinationFormat'] = opts[:destination_format].to_s.camel_case + x.SourceIds { |x| + x[NS_EWS_TYPES].AlternateId { |x| + x.parent['Format'] = opts[:format].to_s.camel_case + x.parent['Id'] = opts[:id] + x.parent['Mailbox'] = opts[:mailbox] + } + } } - } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) + end end end end diff --git a/lib/ews/soap/exchange_notification.rb b/lib/ews/soap/exchange_notification.rb index f1e09f06..3d38ce47 100644 --- a/lib/ews/soap/exchange_notification.rb +++ b/lib/ews/soap/exchange_notification.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,122 +16,126 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # Exchange Notification operations as listed in the EWS Documentation. - # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx - module ExchangeNotification - include Viewpoint::EWS::SOAP +module Viewpoint + module EWS + module SOAP + # Exchange Notification operations as listed in the EWS Documentation. + # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx + module ExchangeNotification + include Viewpoint::EWS::SOAP - # Used to subscribe client applications to either push, pull or stream notifications. - # @see http://msdn.microsoft.com/en-us/library/aa566188(v=EXCHG.140).aspx - # @param [Array] subscriptions An array of Hash objects that describe each - # subscription. - # Ex: [ {:pull_subscription_request => { - # :subscribe_to_all_folders => false, - # :folder_ids => [ {:id => 'id', :change_key => 'ck'} ], - # :event_types=> %w{CopiedEvent CreatedEvent}, - # :watermark => 'watermark id', - # :timeout => intval - # }}, - # {:push_subscription_request => { - # :subscribe_to_all_folders => true, - # :event_types=> %w{CopiedEvent CreatedEvent}, - # :status_frequency => 15, - # :uRL => 'http://my.endpoint.for.updates/', - # }}, - # {:streaming_subscription_request => { - # :subscribe_to_all_folders => false, - # :folder_ids => [ {:id => 'id', :change_key => 'ck'} ], - # :event_types=> %w{NewMailEvent DeletedEvent}, - # }}, - # ] - def subscribe(subscriptions) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.Subscribe { - builder.nbuild.parent.default_namespace = @default_ns - subscriptions.each do |sub| - subtype = sub.keys.first - raise EwsBadArgumentError, "Bad subscription type. #{subtype}" unless builder.respond_to?(subtype) + # Used to subscribe client applications to either push, pull or stream notifications. + # @see http://msdn.microsoft.com/en-us/library/aa566188(v=EXCHG.140).aspx + # @param [Array] subscriptions An array of Hash objects that describe each + # subscription. + # Ex: [ {:pull_subscription_request => { + # :subscribe_to_all_folders => false, + # :folder_ids => [ {:id => 'id', :change_key => 'ck'} ], + # :event_types=> %w{CopiedEvent CreatedEvent}, + # :watermark => 'watermark id', + # :timeout => intval + # }}, + # {:push_subscription_request => { + # :subscribe_to_all_folders => true, + # :event_types=> %w{CopiedEvent CreatedEvent}, + # :status_frequency => 15, + # :uRL => 'http://my.endpoint.for.updates/', + # }}, + # {:streaming_subscription_request => { + # :subscribe_to_all_folders => false, + # :folder_ids => [ {:id => 'id', :change_key => 'ck'} ], + # :event_types=> %w{NewMailEvent DeletedEvent}, + # }}, + # ] + def subscribe(subscriptions) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.Subscribe { + builder.nbuild.parent.default_namespace = @default_ns + subscriptions.each do |sub| + subtype = sub.keys.first + raise EwsBadArgumentError, "Bad subscription type. #{subtype}" unless builder.respond_to?(subtype) - builder.send subtype, sub[subtype] + builder.send subtype, sub[subtype] + end + } end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # End a pull notification subscription. - # @see http://msdn.microsoft.com/en-us/library/aa564263.aspx - # - # @param [String] subscription_id The Id of the subscription - def unsubscribe(subscription_id) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.Unsubscribe { - builder.nbuild.parent.default_namespace = @default_ns - builder.subscription_id!(subscription_id) + # End a pull notification subscription. + # @see http://msdn.microsoft.com/en-us/library/aa564263.aspx + # + # @param [String] subscription_id The Id of the subscription + def unsubscribe(subscription_id) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.Unsubscribe { + builder.nbuild.parent.default_namespace = @default_ns + builder.subscription_id!(subscription_id) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Used by pull subscription clients to request notifications from the Client Access server - # @see http://msdn.microsoft.com/en-us/library/aa566199.aspx GetEvents on MSDN - # - # @param [String] subscription_id Subscription identifier - # @param [String] watermark Event bookmark in the events queue - def get_events(subscription_id, watermark) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetEvents { - builder.nbuild.parent.default_namespace = @default_ns - builder.subscription_id!(subscription_id) - builder.watermark!(watermark, NS_EWS_MESSAGES) + # Used by pull subscription clients to request notifications from the Client Access server + # @see http://msdn.microsoft.com/en-us/library/aa566199.aspx GetEvents on MSDN + # + # @param [String] subscription_id Subscription identifier + # @param [String] watermark Event bookmark in the events queue + def get_events(subscription_id, watermark) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetEvents { + builder.nbuild.parent.default_namespace = @default_ns + builder.subscription_id!(subscription_id) + builder.watermark!(watermark, NS_EWS_MESSAGES) + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # ------- convenience methods ------- # + # ------- convenience methods ------- # - # Create a pull subscription to a single folder - # @param folder [Hash] a hash with the folder :id and :change_key - # @param evtypes [Array] the events you would like to subscribe to. - # @param timeout [Fixnum] http://msdn.microsoft.com/en-us/library/aa565201.aspx - # @param watermark [String] http://msdn.microsoft.com/en-us/library/aa565886.aspx - def pull_subscribe_folder(folder, evtypes, timeout = nil, watermark = nil) - timeout ||= 240 # 4 hour default timeout - psr = { - subscribe_to_all_folders: false, - folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], - event_types: evtypes, - timeout: timeout - } - psr[:watermark] = watermark if watermark - subscribe([{ pull_subscription_request: psr }]) - end + # Create a pull subscription to a single folder + # @param folder [Hash] a hash with the folder :id and :change_key + # @param evtypes [Array] the events you would like to subscribe to. + # @param timeout [Fixnum] http://msdn.microsoft.com/en-us/library/aa565201.aspx + # @param watermark [String] http://msdn.microsoft.com/en-us/library/aa565886.aspx + def pull_subscribe_folder(folder, evtypes, timeout = nil, watermark = nil) + timeout ||= 240 # 4 hour default timeout + psr = { + subscribe_to_all_folders: false, + folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], + event_types: evtypes, + timeout: timeout + } + psr[:watermark] = watermark if watermark + subscribe([{ pull_subscription_request: psr }]) + end - # Create a push subscription to a single folder - # @param folder [Hash] a hash with the folder :id and :change_key - # @param evtypes [Array] the events you would like to subscribe to. - # @param url [String,URI] http://msdn.microsoft.com/en-us/library/aa566309.aspx - # @param watermark [String] http://msdn.microsoft.com/en-us/library/aa565886.aspx - # @param status_frequency [Fixnum] http://msdn.microsoft.com/en-us/library/aa564048.aspx - def push_subscribe_folder(folder, evtypes, url, status_frequency = nil, watermark = nil) - status_frequency ||= 30 - psr = { - subscribe_to_all_folders: false, - folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], - event_types: evtypes, - status_frequency: status_frequency, - uRL: url.to_s - } - psr[:watermark] = watermark if watermark - subscribe([{ push_subscription_request: psr }]) + # Create a push subscription to a single folder + # @param folder [Hash] a hash with the folder :id and :change_key + # @param evtypes [Array] the events you would like to subscribe to. + # @param url [String,URI] http://msdn.microsoft.com/en-us/library/aa566309.aspx + # @param watermark [String] http://msdn.microsoft.com/en-us/library/aa565886.aspx + # @param status_frequency [Fixnum] http://msdn.microsoft.com/en-us/library/aa564048.aspx + def push_subscribe_folder(folder, evtypes, url, status_frequency = nil, watermark = nil) + status_frequency ||= 30 + psr = { + subscribe_to_all_folders: false, + folder_ids: [{ id: folder[:id], change_key: folder[:change_key] }], + event_types: evtypes, + status_frequency: status_frequency, + uRL: url.to_s + } + psr[:watermark] = watermark if watermark + subscribe([{ push_subscription_request: psr }]) + end + end end end end diff --git a/lib/ews/soap/exchange_synchronization.rb b/lib/ews/soap/exchange_synchronization.rb index 01e47b26..95ca06f5 100644 --- a/lib/ews/soap/exchange_synchronization.rb +++ b/lib/ews/soap/exchange_synchronization.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,74 +16,78 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # Exchange Synchronization operations as listed in the EWS Documentation. - # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx - module ExchangeSynchronization - include Viewpoint::EWS::SOAP +module Viewpoint + module EWS + module SOAP + # Exchange Synchronization operations as listed in the EWS Documentation. + # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx + module ExchangeSynchronization + include Viewpoint::EWS::SOAP - # Defines a request to synchronize a folder hierarchy on a client - # @see http://msdn.microsoft.com/en-us/library/aa580990.aspx - # @param [Hash] opts - # @option opts [Hash] :folder_shape The folder shape properties - # Ex: {:base_shape => 'Default', :additional_properties => 'bla bla bla'} - # @option opts [Hash] :sync_folder_id An optional Hash that represents a FolderId or - # DistinguishedFolderId. - # Ex: {:id => :inbox} - # @option opts [Hash] :sync_state The Base64 sync state id. If this is the - # first time syncing this does not need to be passed. - def sync_folder_hierarchy(opts) - opts = opts.clone - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.SyncFolderHierarchy { - builder.nbuild.parent.default_namespace = @default_ns - builder.folder_shape!(opts[:folder_shape]) - builder.sync_folder_id!(opts[:sync_folder_id]) if opts[:sync_folder_id] - builder.sync_state!(opts[:sync_state]) if opts[:sync_state] + # Defines a request to synchronize a folder hierarchy on a client + # @see http://msdn.microsoft.com/en-us/library/aa580990.aspx + # @param [Hash] opts + # @option opts [Hash] :folder_shape The folder shape properties + # Ex: {:base_shape => 'Default', :additional_properties => 'bla bla bla'} + # @option opts [Hash] :sync_folder_id An optional Hash that represents a FolderId or + # DistinguishedFolderId. + # Ex: {:id => :inbox} + # @option opts [Hash] :sync_state The Base64 sync state id. If this is the + # first time syncing this does not need to be passed. + def sync_folder_hierarchy(opts) + opts = opts.clone + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.SyncFolderHierarchy { + builder.nbuild.parent.default_namespace = @default_ns + builder.folder_shape!(opts[:folder_shape]) + builder.sync_folder_id!(opts[:sync_folder_id]) if opts[:sync_folder_id] + builder.sync_state!(opts[:sync_state]) if opts[:sync_state] + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) - end - # Synchronizes items between the Exchange server and the client - # @see http://msdn.microsoft.com/en-us/library/aa563967(v=EXCHG.140).aspx - # @param [Hash] opts - # @option opts [Hash] :item_shape The item shape properties - # Ex: {:base_shape => 'Default', :additional_properties => 'bla bla bla'} - # @option opts [Hash] :sync_folder_id A Hash that represents a FolderId or - # DistinguishedFolderId. [ Ex: {:id => :inbox} ] OPTIONAL - # @option opts [String] :sync_state The Base64 sync state id. If this is the - # first time syncing this does not need to be passed. OPTIONAL on first call - # @option opts [Array ] :ignore An Array of ItemIds for items to ignore - # during the sync process. Ex: [{:id => 'id1', :change_key => 'ck'}, {:id => 'id2'}] - # OPTIONAL - # @option opts [Integer] :max_changes_returned ('required') The amount of items to sync per call. - # @option opts [String] :sync_scope specifies whether just items or items and folder associated - # information are returned. OPTIONAL - # options: 'NormalItems' or 'NormalAndAssociatedItems' - # @example - # { :item_shape => {:base_shape => 'Default'}, - # :sync_folder_id => {:id => :inbox}, - # :sync_state => myBase64id, - # :max_changes_returned => 256 } - def sync_folder_items(opts) - opts = opts.clone - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.SyncFolderItems { - builder.nbuild.parent.default_namespace = @default_ns - builder.item_shape!(opts[:item_shape]) - builder.sync_folder_id!(opts[:sync_folder_id]) if opts[:sync_folder_id] - builder.sync_state!(opts[:sync_state]) if opts[:sync_state] - builder.ignore!(opts[:ignore]) if opts[:ignore] - builder.max_changes_returned!(opts[:max_changes_returned]) - builder.sync_scope!(opts[:sync_scope]) if opts[:sync_scope] + # Synchronizes items between the Exchange server and the client + # @see http://msdn.microsoft.com/en-us/library/aa563967(v=EXCHG.140).aspx + # @param [Hash] opts + # @option opts [Hash] :item_shape The item shape properties + # Ex: {:base_shape => 'Default', :additional_properties => 'bla bla bla'} + # @option opts [Hash] :sync_folder_id A Hash that represents a FolderId or + # DistinguishedFolderId. [ Ex: {:id => :inbox} ] OPTIONAL + # @option opts [String] :sync_state The Base64 sync state id. If this is the + # first time syncing this does not need to be passed. OPTIONAL on first call + # @option opts [Array ] :ignore An Array of ItemIds for items to ignore + # during the sync process. Ex: [{:id => 'id1', :change_key => 'ck'}, {:id => 'id2'}] + # OPTIONAL + # @option opts [Integer] :max_changes_returned ('required') The amount of items to sync per call. + # @option opts [String] :sync_scope specifies whether just items or items and folder associated + # information are returned. OPTIONAL + # options: 'NormalItems' or 'NormalAndAssociatedItems' + # @example + # { :item_shape => {:base_shape => 'Default'}, + # :sync_folder_id => {:id => :inbox}, + # :sync_state => myBase64id, + # :max_changes_returned => 256 } + def sync_folder_items(opts) + opts = opts.clone + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.SyncFolderItems { + builder.nbuild.parent.default_namespace = @default_ns + builder.item_shape!(opts[:item_shape]) + builder.sync_folder_id!(opts[:sync_folder_id]) if opts[:sync_folder_id] + builder.sync_state!(opts[:sync_state]) if opts[:sync_state] + builder.ignore!(opts[:ignore]) if opts[:ignore] + builder.max_changes_returned!(opts[:max_changes_returned]) + builder.sync_scope!(opts[:sync_scope]) if opts[:sync_scope] + } + end } + do_soap_request(req, response_class: EwsResponse) end - } - do_soap_request(req, response_class: EwsResponse) + end end end end diff --git a/lib/ews/soap/exchange_time_zones.rb b/lib/ews/soap/exchange_time_zones.rb index 7d1d1bcf..6bc479a8 100644 --- a/lib/ews/soap/exchange_time_zones.rb +++ b/lib/ews/soap/exchange_time_zones.rb @@ -1,47 +1,52 @@ # frozen_string_literal: true -module Viewpoint::EWS::SOAP - module ExchangeTimeZones - include Viewpoint::EWS::SOAP - # Request list of server known time zones - # @param full [Boolean] Request full time zone definition? Returns only name and id if false. - # @param ids [Array] Returns only the specified time zones instead of all if present - # @return [Array] Array of Objects responding to #id() and #name() - # @example Retrieving server time zones - # ews_client = Viewpoint::EWSClient.new # ... - # zones = ews_client.ews.get_time_zones - # @todo Implement TimeZoneDefinition with sub elements Periods, TransitionsGroups and Transitions - def get_time_zones(full = false, ids = nil) - req = build_soap! { |type, builder| - builder.get_server_time_zones!(full: full, ids: ids) unless type == :header - } - result = do_soap_request req, response_class: EwsSoapResponse +module Viewpoint + module EWS + module SOAP + module ExchangeTimeZones + include Viewpoint::EWS::SOAP - raise EwsError, 'Could not get time zones' unless result.success? - - zones = [] - result.response_messages.each do |message| - elements = message[:get_server_time_zones_response_message][:elems][:time_zone_definitions][:elems] - elements.each do |definition| - data = { - id: definition[:time_zone_definition][:attribs][:id], - name: definition[:time_zone_definition][:attribs][:name] + # Request list of server known time zones + # @param full [Boolean] Request full time zone definition? Returns only name and id if false. + # @param ids [Array] Returns only the specified time zones instead of all if present + # @return [Array] Array of Objects responding to #id() and #name() + # @example Retrieving server time zones + # ews_client = Viewpoint::EWSClient.new # ... + # zones = ews_client.ews.get_time_zones + # @todo Implement TimeZoneDefinition with sub elements Periods, TransitionsGroups and Transitions + def get_time_zones(full = false, ids = nil) + req = build_soap! { |type, builder| + builder.get_server_time_zones!(full: full, ids: ids) unless type == :header } - zones << OpenStruct.new(data) + result = do_soap_request req, response_class: EwsSoapResponse + + raise EwsError, 'Could not get time zones' unless result.success? + + zones = [] + result.response_messages.each do |message| + elements = message[:get_server_time_zones_response_message][:elems][:time_zone_definitions][:elems] + elements.each do |definition| + data = { + id: definition[:time_zone_definition][:attribs][:id], + name: definition[:time_zone_definition][:attribs][:name] + } + zones << OpenStruct.new(data) + end + end + zones end - end - zones - end - # Sets the time zone context header - # @param id [String] Identifier of a Microsoft well known time zone - # @example Set time zone context for connection - # ews_client = Viewpoint::EWSClient.new # ... - # ews_client.set_time_zone 'AUS Central Standard Time' - # # subsequent request will send the TimeZoneContext header - # @see EWSClient#set_time_zone - def set_time_zone_context(id) - @time_zone_context = ({ id: id } if id) + # Sets the time zone context header + # @param id [String] Identifier of a Microsoft well known time zone + # @example Set time zone context for connection + # ews_client = Viewpoint::EWSClient.new # ... + # ews_client.set_time_zone 'AUS Central Standard Time' + # # subsequent request will send the TimeZoneContext header + # @see EWSClient#set_time_zone + def set_time_zone_context(id) + @time_zone_context = ({ id: id } if id) + end + end end end end diff --git a/lib/ews/soap/exchange_user_configuration.rb b/lib/ews/soap/exchange_user_configuration.rb index a8223e31..cc7acc64 100644 --- a/lib/ews/soap/exchange_user_configuration.rb +++ b/lib/ews/soap/exchange_user_configuration.rb @@ -1,31 +1,36 @@ # frozen_string_literal: true -module Viewpoint::EWS::SOAP - # Exchange User Configuration operations as listed in the EWS Documentation. - # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx - module ExchangeUserConfiguration - include Viewpoint::EWS::SOAP - # The GetUserConfiguration operation gets a user configuration object from - # a folder. - # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx - # @param [Hash] opts - # @option opts [Hash] :user_config_name - # @option opts [String] :user_config_props - def get_user_configuration(opts) - opts = opts.clone - %i[user_config_name user_config_props].each do |k| - validate_param(opts, k, true) - end - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetUserConfiguration { |x| - x.parent.default_namespace = @default_ns - builder.user_configuration_name!(opts[:user_config_name]) - builder.user_configuration_properties!(opts[:user_config_props]) +module Viewpoint + module EWS + module SOAP + # Exchange User Configuration operations as listed in the EWS Documentation. + # @see http://msdn.microsoft.com/en-us/library/bb409286.aspx + module ExchangeUserConfiguration + include Viewpoint::EWS::SOAP + + # The GetUserConfiguration operation gets a user configuration object from + # a folder. + # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx + # @param [Hash] opts + # @option opts [Hash] :user_config_name + # @option opts [String] :user_config_props + def get_user_configuration(opts) + opts = opts.clone + %i[user_config_name user_config_props].each do |k| + validate_param(opts, k, true) + end + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserConfiguration { |x| + x.parent.default_namespace = @default_ns + builder.user_configuration_name!(opts[:user_config_name]) + builder.user_configuration_properties!(opts[:user_config_props]) + } + end } + do_soap_request(req, response_class: EwsSoapAvailabilityResponse) end - } - do_soap_request(req, response_class: EwsSoapAvailabilityResponse) + end end end end diff --git a/lib/ews/soap/exchange_web_service.rb b/lib/ews/soap/exchange_web_service.rb index 599c532d..16f1430c 100644 --- a/lib/ews/soap/exchange_web_service.rb +++ b/lib/ews/soap/exchange_web_service.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,248 +16,252 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class ExchangeWebService - include Viewpoint::EWS - include Viewpoint::EWS::SOAP - include Viewpoint::StringUtils - include ExchangeDataServices - include ExchangeNotification - include ExchangeAvailability - include ExchangeUserConfiguration - include ExchangeSynchronization - include ExchangeTimeZones - - attr_accessor :server_version, :auto_deepen, :no_auto_deepen_behavior, :connection, :impersonation_type, - :impersonation_address +module Viewpoint + module EWS + module SOAP + class ExchangeWebService + include Viewpoint::EWS + include Viewpoint::EWS::SOAP + include Viewpoint::StringUtils + include ExchangeDataServices + include ExchangeNotification + include ExchangeAvailability + include ExchangeUserConfiguration + include ExchangeSynchronization + include ExchangeTimeZones - # @param [Viewpoint::EWS::Connection] connection the connection object - # @param [Hash] opts additional options to the web service - # @option opts [String] :server_version what version to target with the - # requests. Must be one of the contants VERSION_2007, VERSION_2007_SP1, - # VERSION_2010, VERSION_2010_SP1, VERSION_2010_SP2, or VERSION_NONE. The - # default is VERSION_2010. - def initialize(connection, opts = {}) - super() - @connection = connection - @server_version = opts[:server_version] || VERSION_2010 - @auto_deepen = true - @no_auto_deepen_behavior = :raise - @impersonation_type = '' - @impersonation_address = '' - end + attr_accessor :server_version, :auto_deepen, :no_auto_deepen_behavior, :connection, :impersonation_type, + :impersonation_address - def delete_attachment - action = "#{SOAP_ACTION_PREFIX}/DeleteAttachment" - resp = invoke("#{NS_EWS_MESSAGES}:DeleteAttachment", action) { |delete_attachment| - build_delete_attachment!(delete_attachment) - } - parse_delete_attachment(resp) - end + # @param [Viewpoint::EWS::Connection] connection the connection object + # @param [Hash] opts additional options to the web service + # @option opts [String] :server_version what version to target with the + # requests. Must be one of the contants VERSION_2007, VERSION_2007_SP1, + # VERSION_2010, VERSION_2010_SP1, VERSION_2010_SP2, or VERSION_NONE. The + # default is VERSION_2010. + def initialize(connection, opts = {}) + super() + @connection = connection + @server_version = opts[:server_version] || VERSION_2010 + @auto_deepen = true + @no_auto_deepen_behavior = :raise + @impersonation_type = '' + @impersonation_address = '' + end - def create_managed_folder - action = "#{SOAP_ACTION_PREFIX}/CreateManagedFolder" - resp = invoke("#{NS_EWS_MESSAGES}:CreateManagedFolder", action) { |create_managed_folder| - build_create_managed_folder!(create_managed_folder) - } - parse_create_managed_folder(resp) - end + def delete_attachment + action = "#{SOAP_ACTION_PREFIX}/DeleteAttachment" + resp = invoke("#{NS_EWS_MESSAGES}:DeleteAttachment", action) { |delete_attachment| + build_delete_attachment!(delete_attachment) + } + parse_delete_attachment(resp) + end - # Retrieves the delegate settings for a specific mailbox. - # @see http://msdn.microsoft.com/en-us/library/bb799735.aspx - # - # @param [String] owner The user that is delegating permissions - def get_delegate(owner) - action = "#{SOAP_ACTION_PREFIX}/GetDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:GetDelegate", action) { |root| - root.set_attr('IncludePermissions', 'true') - build!(root) do - mailbox!(root, { email_address: { text: owner } }) + def create_managed_folder + action = "#{SOAP_ACTION_PREFIX}/CreateManagedFolder" + resp = invoke("#{NS_EWS_MESSAGES}:CreateManagedFolder", action) { |create_managed_folder| + build_create_managed_folder!(create_managed_folder) + } + parse_create_managed_folder(resp) end - } - parse_soap_response(resp) - end - # Adds one or more delegates to a principal's mailbox and sets specific access permissions. - # @see http://msdn.microsoft.com/en-us/library/bb856527.aspx - # - # @param [String] owner The user that is delegating permissions - # @param [String] delegate The user that is being given delegate permission - # @param [Hash] permissions A hash of permissions that will be delegated. - # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. - def add_delegate(owner, delegate, permissions) - action = "#{SOAP_ACTION_PREFIX}/AddDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:AddDelegate", action) { |root| - build!(root) do - add_delegate!(owner, delegate, permissions) + # Retrieves the delegate settings for a specific mailbox. + # @see http://msdn.microsoft.com/en-us/library/bb799735.aspx + # + # @param [String] owner The user that is delegating permissions + def get_delegate(owner) + action = "#{SOAP_ACTION_PREFIX}/GetDelegate" + resp = invoke("#{NS_EWS_MESSAGES}:GetDelegate", action) { |root| + root.set_attr('IncludePermissions', 'true') + build!(root) do + mailbox!(root, { email_address: { text: owner } }) + end + } + parse_soap_response(resp) end - } - parse_soap_response(resp) - end - # Removes one or more delegates from a user's mailbox. - # @see http://msdn.microsoft.com/en-us/library/bb856564.aspx - # - # @param [String] owner The user that is delegating permissions - # @param [String] delegate The user that is being given delegate permission - def remove_delegate(owner, delegate) - action = "#{SOAP_ACTION_PREFIX}/RemoveDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:RemoveDelegate", action) { |root| - build!(root) do - remove_delegate!(owner, delegate) + # Adds one or more delegates to a principal's mailbox and sets specific access permissions. + # @see http://msdn.microsoft.com/en-us/library/bb856527.aspx + # + # @param [String] owner The user that is delegating permissions + # @param [String] delegate The user that is being given delegate permission + # @param [Hash] permissions A hash of permissions that will be delegated. + # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. + def add_delegate(owner, delegate, permissions) + action = "#{SOAP_ACTION_PREFIX}/AddDelegate" + resp = invoke("#{NS_EWS_MESSAGES}:AddDelegate", action) { |root| + build!(root) do + add_delegate!(owner, delegate, permissions) + end + } + parse_soap_response(resp) end - } - parse_soap_response(resp) - end - # Updates delegate permissions on a principal's mailbox - # @see http://msdn.microsoft.com/en-us/library/bb856529.aspx - # - # @param [String] owner The user that is delegating permissions - # @param [String] delegate The user that is being given delegate permission - # @param [Hash] permissions A hash of permissions that will be delegated. - # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. - def update_delegate(owner, delegate, permissions) - action = "#{SOAP_ACTION_PREFIX}/UpdateDelegate" - resp = invoke("#{NS_EWS_MESSAGES}:UpdateDelegate", action) { |root| - build!(root) do - add_delegate!(owner, delegate, permissions) + # Removes one or more delegates from a user's mailbox. + # @see http://msdn.microsoft.com/en-us/library/bb856564.aspx + # + # @param [String] owner The user that is delegating permissions + # @param [String] delegate The user that is being given delegate permission + def remove_delegate(owner, delegate) + action = "#{SOAP_ACTION_PREFIX}/RemoveDelegate" + resp = invoke("#{NS_EWS_MESSAGES}:RemoveDelegate", action) { |root| + build!(root) do + remove_delegate!(owner, delegate) + end + } + parse_soap_response(resp) end - } - parse_soap_response(resp) - end - # Provides detailed information about the availability of a set of users, rooms, and resources - # within a specified time window. - # @see http://msdn.microsoft.com/en-us/library/aa564001.aspx - # @param [Hash] opts - # @option opts [Hash] :time_zone The TimeZone data - # Example: {:bias => 'UTC offset in minutes', - # :standard_time => {:bias => 480, :time => '02:00:00', - # :day_order => 5, :month => 10, :day_of_week => 'Sunday'}, - # :daylight_time => {same options as :standard_time}} - # @option opts [Array] :mailbox_data Data for the mailbox to query - # Example: [{:attendee_type => 'Organizer|Required|Optional|Room|Resource', - # :email =>{:name => 'name', :address => 'email', :routing_type => 'SMTP'}, - # :exclude_conflicts => true|false }] - # @option opts [Hash] :free_busy_view_options - # Example: {:time_window => {:start_time => DateTime,:end_time => DateTime}, - # :merged_free_busy_interval_in_minutes => minute_int, - # :requested_view => None|MergedOnly|FreeBusy|FreeBusyMerged|Detailed - # |DetailedMerged} (optional) - # @option opts [Hash] :suggestions_view_options (optional) - # @todo Finish out :suggestions_view_options - def get_user_availability(opts) - opts = opts.clone - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetUserAvailabilityRequest { |x| - x.parent.default_namespace = @default_ns - builder.time_zone!(opts[:time_zone]) - builder.nbuild.MailboxDataArray do - opts[:mailbox_data].each do |mbd| - builder.mailbox_data!(mbd) - end + # Updates delegate permissions on a principal's mailbox + # @see http://msdn.microsoft.com/en-us/library/bb856529.aspx + # + # @param [String] owner The user that is delegating permissions + # @param [String] delegate The user that is being given delegate permission + # @param [Hash] permissions A hash of permissions that will be delegated. + # This Hash will eventually be passed to add_hierarchy! in the builder so it is in that format. + def update_delegate(owner, delegate, permissions) + action = "#{SOAP_ACTION_PREFIX}/UpdateDelegate" + resp = invoke("#{NS_EWS_MESSAGES}:UpdateDelegate", action) { |root| + build!(root) do + add_delegate!(owner, delegate, permissions) end - builder.free_busy_view_options!(opts[:free_busy_view_options]) - builder.suggestions_view_options!(opts[:suggestions_view_options]) } + parse_soap_response(resp) end - } - do_soap_request(req, response_class: EwsSoapFreeBusyResponse) - end + # Provides detailed information about the availability of a set of users, rooms, and resources + # within a specified time window. + # @see http://msdn.microsoft.com/en-us/library/aa564001.aspx + # @param [Hash] opts + # @option opts [Hash] :time_zone The TimeZone data + # Example: {:bias => 'UTC offset in minutes', + # :standard_time => {:bias => 480, :time => '02:00:00', + # :day_order => 5, :month => 10, :day_of_week => 'Sunday'}, + # :daylight_time => {same options as :standard_time}} + # @option opts [Array] :mailbox_data Data for the mailbox to query + # Example: [{:attendee_type => 'Organizer|Required|Optional|Room|Resource', + # :email =>{:name => 'name', :address => 'email', :routing_type => 'SMTP'}, + # :exclude_conflicts => true|false }] + # @option opts [Hash] :free_busy_view_options + # Example: {:time_window => {:start_time => DateTime,:end_time => DateTime}, + # :merged_free_busy_interval_in_minutes => minute_int, + # :requested_view => None|MergedOnly|FreeBusy|FreeBusyMerged|Detailed + # |DetailedMerged} (optional) + # @option opts [Hash] :suggestions_view_options (optional) + # @todo Finish out :suggestions_view_options + def get_user_availability(opts) + opts = opts.clone + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetUserAvailabilityRequest { |x| + x.parent.default_namespace = @default_ns + builder.time_zone!(opts[:time_zone]) + builder.nbuild.MailboxDataArray do + opts[:mailbox_data].each do |mbd| + builder.mailbox_data!(mbd) + end + end + builder.free_busy_view_options!(opts[:free_busy_view_options]) + builder.suggestions_view_options!(opts[:suggestions_view_options]) + } + end + } - # Gets the rooms that are in the specified room distribution list - # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx - # @param [string] roomDistributionList - def get_rooms(roomDistributionList) - req = build_soap! { |type, builder| - unless type == :header - builder.nbuild.GetRooms { |x| - x.parent.default_namespace = @default_ns - builder.room_list!(roomDistributionList) + do_soap_request(req, response_class: EwsSoapFreeBusyResponse) + end + + # Gets the rooms that are in the specified room distribution list + # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx + # @param [string] roomDistributionList + def get_rooms(roomDistributionList) + req = build_soap! { |type, builder| + unless type == :header + builder.nbuild.GetRooms { |x| + x.parent.default_namespace = @default_ns + builder.room_list!(roomDistributionList) + } + end } + do_soap_request(req, response_class: EwsSoapRoomResponse) end - } - do_soap_request(req, response_class: EwsSoapRoomResponse) - end - # Gets the room lists that are available within the Exchange organization. - # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx - def get_room_lists - req = build_soap! { |type, builder| - builder.room_lists! unless type == :header - } - do_soap_request(req, response_class: EwsSoapRoomlistResponse) - end + # Gets the room lists that are available within the Exchange organization. + # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx + def get_room_lists + req = build_soap! { |type, builder| + builder.room_lists! unless type == :header + } + do_soap_request(req, response_class: EwsSoapRoomlistResponse) + end - # Send the SOAP request to the endpoint and parse it. - # @param [String] soapmsg an XML formatted string - # @todo make this work for Viewpoint (imported from SPWS) - # @param [Hash] opts misc options - # @option opts [Boolean] :raw_response if true do not parse and return - # the raw response string. - def do_soap_request(soapmsg, opts = {}) - @log.debug <<-EOF.gsub(/^ {8}/, '') + # Send the SOAP request to the endpoint and parse it. + # @param [String] soapmsg an XML formatted string + # @todo make this work for Viewpoint (imported from SPWS) + # @param [Hash] opts misc options + # @option opts [Boolean] :raw_response if true do not parse and return + # the raw response string. + def do_soap_request(soapmsg, opts = {}) + @log.debug <<-EOF.gsub(/^ {8}/, '') Sending SOAP Request: ---------------- #{soapmsg} ---------------- - EOF - connection.dispatch(self, soapmsg, opts) - end + EOF + connection.dispatch(self, soapmsg, opts) + end - # @param [String] response the SOAP response string - # @param [Hash] opts misc options to send to the parser - # @option opts [Class] :response_class the response class - def parse_soap_response(soapmsg, opts = {}) - raise EwsError, "Can't parse an empty response. Please check your endpoint." if soapmsg.nil? + # @param [String] response the SOAP response string + # @param [Hash] opts misc options to send to the parser + # @option opts [Class] :response_class the response class + def parse_soap_response(soapmsg, opts = {}) + raise EwsError, "Can't parse an empty response. Please check your endpoint." if soapmsg.nil? - opts[:response_class] ||= EwsSoapResponse - EwsParser.new(soapmsg).parse(opts) - end + opts[:response_class] ||= EwsSoapResponse + EwsParser.new(soapmsg).parse(opts) + end - private + private - # Private Methods (Builders and Parsers) + # Private Methods (Builders and Parsers) - # Validate or set default values for options parameters. - # @param [Hash] opts The options parameter passed to an EWS operation - # @param [Symbol] key The key in the Hash we are validating - # @param [Boolean] required Whether or not this key is required - # @param [Object] default_val If the key is not required use this as a - # default value for the operation. - def validate_param(opts, key, required, default_val = nil) - if required - raise EwsBadArgumentError, "Required parameter(#{key}) not passed." unless opts.has_key?(key) + # Validate or set default values for options parameters. + # @param [Hash] opts The options parameter passed to an EWS operation + # @param [Symbol] key The key in the Hash we are validating + # @param [Boolean] required Whether or not this key is required + # @param [Object] default_val If the key is not required use this as a + # default value for the operation. + def validate_param(opts, key, required, default_val = nil) + if required + raise EwsBadArgumentError, "Required parameter(#{key}) not passed." unless opts.has_key?(key) - opts[key] - else - raise EwsBadArgumentError, 'Default value not supplied.' unless default_val + opts[key] + else + raise EwsBadArgumentError, 'Default value not supplied.' unless default_val - opts.has_key?(key) ? opts[key] : default_val - end - end + opts.has_key?(key) ? opts[key] : default_val + end + end - # Some operations only exist for certain versions of Exchange Server. - # This method should be called with the required version and we'll throw - # an exception of the currently set @server_version does not comply. - def validate_version(exchange_version) - return unless server_version < exchange_version + # Some operations only exist for certain versions of Exchange Server. + # This method should be called with the required version and we'll throw + # an exception of the currently set @server_version does not comply. + def validate_version(exchange_version) + return unless server_version < exchange_version - msg = +'The operation you are attempting to use is not compatible with' - msg << " your configured Exchange Server version(#{server_version})." - msg << " You must be running at least version (#{exchange_version})." - raise EwsServerVersionError, msg - end + msg = +'The operation you are attempting to use is not compatible with' + msg << " your configured Exchange Server version(#{server_version})." + msg << " You must be running at least version (#{exchange_version})." + raise EwsServerVersionError, msg + end - # Build the common elements in the SOAP message and yield to any custom elements. - def build_soap!(&block) - opts = { server_version: server_version, impersonation_type: impersonation_type, -impersonation_mail: impersonation_address } - opts[:time_zone_context] = @time_zone_context if @time_zone_context - EwsBuilder.new.build!(opts, &block) + # Build the common elements in the SOAP message and yield to any custom elements. + def build_soap!(&block) + opts = { server_version: server_version, impersonation_type: impersonation_type, + impersonation_mail: impersonation_address } + opts[:time_zone_context] = @time_zone_context if @time_zone_context + EwsBuilder.new.build!(opts, &block) + end + end end end end diff --git a/lib/ews/soap/parsers/ews_parser.rb b/lib/ews/soap/parsers/ews_parser.rb index 90b79eba..1ee8d788 100644 --- a/lib/ews/soap/parsers/ews_parser.rb +++ b/lib/ews/soap/parsers/ews_parser.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,27 +16,31 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class EwsParser - include Viewpoint::EWS +module Viewpoint + module EWS + module SOAP + class EwsParser + include Viewpoint::EWS - # @param [String] soap_resp - def initialize(soap_resp) - @soap_resp = soap_resp - @sax_doc = EwsSaxDocument.new - end + # @param [String] soap_resp + def initialize(soap_resp) + @soap_resp = soap_resp + @sax_doc = EwsSaxDocument.new + end - def parse(opts = {}) - opts[:response_class] ||= EwsSoapResponse - @soap_resp.gsub!(/&#x([0-8bcef]|1[0-9a-f]);/i, '') - sax_parser.parse(@soap_resp) - opts[:response_class].new @sax_doc.struct - end + def parse(opts = {}) + opts[:response_class] ||= EwsSoapResponse + @soap_resp.gsub!(/&#x([0-8bcef]|1[0-9a-f]);/i, '') + sax_parser.parse(@soap_resp) + opts[:response_class].new @sax_doc.struct + end - private + private - def sax_parser - @parser ||= Nokogiri::XML::SAX::Parser.new(@sax_doc) + def sax_parser + @parser ||= Nokogiri::XML::SAX::Parser.new(@sax_doc) + end + end end end end diff --git a/lib/ews/soap/parsers/ews_sax_document.rb b/lib/ews/soap/parsers/ews_sax_document.rb index 4f8349d6..3672a309 100644 --- a/lib/ews/soap/parsers/ews_sax_document.rb +++ b/lib/ews/soap/parsers/ews_sax_document.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,54 +16,58 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - # Parse the incoming response document via a SAX parser instead of the - # traditional DOM parser. In early benchmarks this was performing about - # 132% faster than the DOM-based parser for large documents. - class EwsSaxDocument < Nokogiri::XML::SAX::Document - include Viewpoint::EWS - include Viewpoint::StringUtils +module Viewpoint + module EWS + module SOAP + # Parse the incoming response document via a SAX parser instead of the + # traditional DOM parser. In early benchmarks this was performing about + # 132% faster than the DOM-based parser for large documents. + class EwsSaxDocument < Nokogiri::XML::SAX::Document + include Viewpoint::EWS + include Viewpoint::StringUtils - attr_reader :struct + attr_reader :struct - def initialize - @struct = {} - @elems = [] - end + def initialize + @struct = {} + @elems = [] + end - def characters(string) - # FIXME: Move white space removal to somewhere else. - # This function can be called multiple times. In this case newlines in Text Bodies get stripped. - # See: https://github.com/zenchild/Viewpoint/issues/90 - # string.strip! - return if string.empty? + def characters(string) + # FIXME: Move white space removal to somewhere else. + # This function can be called multiple times. In this case newlines in Text Bodies get stripped. + # See: https://github.com/zenchild/Viewpoint/issues/90 + # string.strip! + return if string.empty? - if @elems.last[:text] - @elems.last[:text] += string - else - @elems.last[:text] = string - end - end + if @elems.last[:text] + @elems.last[:text] += string + else + @elems.last[:text] = string + end + end - def start_element_namespace(name, attributes = [], _prefix = nil, _uri = nil, _ns = []) - ruby_case(name).to_sym - elem = {} - unless attributes.empty? - elem[:attribs] = attributes.collect { |a| - { ruby_case(a.localname).to_sym => a.value } - }.inject(&:merge) - end - @elems << elem - end + def start_element_namespace(name, attributes = [], _prefix = nil, _uri = nil, _ns = []) + ruby_case(name).to_sym + elem = {} + unless attributes.empty? + elem[:attribs] = attributes.collect { |a| + { ruby_case(a.localname).to_sym => a.value } + }.inject(&:merge) + end + @elems << elem + end - def end_element_namespace(name, _prefix = nil, _uri = nil) - name = ruby_case(name).to_sym - elem = @elems.pop - if @elems.empty? - @struct[name] = elem - else - @elems.last[:elems] = [] unless @elems.last[:elems].is_a?(Array) - @elems.last[:elems] << { name => elem } + def end_element_namespace(name, _prefix = nil, _uri = nil) + name = ruby_case(name).to_sym + elem = @elems.pop + if @elems.empty? + @struct[name] = elem + else + @elems.last[:elems] = [] unless @elems.last[:elems].is_a?(Array) + @elems.last[:elems] << { name => elem } + end + end end end end diff --git a/lib/ews/soap/response_message.rb b/lib/ews/soap/response_message.rb index f8808714..94879267 100644 --- a/lib/ews/soap/response_message.rb +++ b/lib/ews/soap/response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,51 +16,55 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class ResponseMessage - attr_reader :message, :type +module Viewpoint + module EWS + module SOAP + class ResponseMessage + attr_reader :message, :type - def initialize(message) - @type = message.keys.first - @message = message[@type] - end + def initialize(message) + @type = message.keys.first + @message = message[@type] + end - def response_class - message[:attribs][:response_class] - end - alias status response_class + def response_class + message[:attribs][:response_class] + end + alias status response_class - def success? - response_class == 'Success' - end + def success? + response_class == 'Success' + end - def message_text - safe_hash_access message, %i[elems message_text text] - end + def message_text + safe_hash_access message, %i[elems message_text text] + end - def response_code - safe_hash_access message, %i[elems response_code text] - end - alias code response_code + def response_code + safe_hash_access message, %i[elems response_code text] + end + alias code response_code - def message_xml - safe_hash_access message, %i[elems message_xml text] - end + def message_xml + safe_hash_access message, %i[elems message_xml text] + end - def items - safe_hash_access(message, %i[elems items elems]) || [] - end + def items + safe_hash_access(message, %i[elems items elems]) || [] + end - private + private - def safe_hash_access(hsh, keys) - key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) + def safe_hash_access(hsh, keys) + key = keys.shift + return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) - if keys.empty? - hsh[key] - else - safe_hash_access hsh[key], keys + if keys.empty? + hsh[key] + else + safe_hash_access hsh[key], keys + end + end end end end diff --git a/lib/ews/soap/responses/create_attachment_response_message.rb b/lib/ews/soap/responses/create_attachment_response_message.rb index b0df1cf1..1c7d0425 100644 --- a/lib/ews/soap/responses/create_attachment_response_message.rb +++ b/lib/ews/soap/responses/create_attachment_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,26 +16,30 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class CreateAttachmentResponseMessage < ResponseMessage - include Viewpoint::StringUtils +module Viewpoint + module EWS + module SOAP + class CreateAttachmentResponseMessage < ResponseMessage + include Viewpoint::StringUtils - def attachments - return @attachments if @attachments + def attachments + return @attachments if @attachments - a = safe_hash_access message, %i[elems attachments elems] - @attachments = a.nil? ? nil : parse_attachments(a) - end + a = safe_hash_access message, %i[elems attachments elems] + @attachments = a.nil? ? nil : parse_attachments(a) + end - private + private - def parse_attachments(att) - att.collect do |a| - type = a.keys.first - klass = Viewpoint::EWS::Types.const_get(camel_case(type)) - item = OpenStruct.new - item.ews = nil - klass.new(item, a[type]) + def parse_attachments(att) + att.collect do |a| + type = a.keys.first + klass = Viewpoint::EWS::Types.const_get(camel_case(type)) + item = OpenStruct.new + item.ews = nil + klass.new(item, a[type]) + end + end end end end diff --git a/lib/ews/soap/responses/create_item_response_message.rb b/lib/ews/soap/responses/create_item_response_message.rb index 1e283cda..87606b8b 100644 --- a/lib/ews/soap/responses/create_item_response_message.rb +++ b/lib/ews/soap/responses/create_item_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,7 +16,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class CreateItemResponseMessage < ResponseMessage +module Viewpoint + module EWS + module SOAP + class CreateItemResponseMessage < ResponseMessage + end + end end end diff --git a/lib/ews/soap/responses/find_item_response_message.rb b/lib/ews/soap/responses/find_item_response_message.rb index 10f73b04..f6a50ef3 100644 --- a/lib/ews/soap/responses/find_item_response_message.rb +++ b/lib/ews/soap/responses/find_item_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,57 +16,61 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class RootFolder - attr_reader :root +module Viewpoint + module EWS + module SOAP + class RootFolder + attr_reader :root - def initialize(root) - @root = root - end + def initialize(root) + @root = root + end - def indexed_paging_offset - attrib :index_paging_offset - end + def indexed_paging_offset + attrib :index_paging_offset + end - def numerator_offset - attrib :numerator_offset - end + def numerator_offset + attrib :numerator_offset + end - def absolute_denominator - attrib :absolute_denominator - end + def absolute_denominator + attrib :absolute_denominator + end - def includes_last_item_in_range - attrib :includes_last_item_in_range - end + def includes_last_item_in_range + attrib :includes_last_item_in_range + end - def total_items_in_view - attrib :total_items_in_view - end + def total_items_in_view + attrib :total_items_in_view + end - def items - root[:elems][0][:items][:elems] || [] - end + def items + root[:elems][0][:items][:elems] || [] + end - def groups - root[:elems][0][:groups][:elems] - end + def groups + root[:elems][0][:groups][:elems] + end - private + private - def attrib(key) - return nil unless root.has_key?(:attribs) + def attrib(key) + return nil unless root.has_key?(:attribs) - root[:attribs][key] - end - end + root[:attribs][key] + end + end - class FindItemResponseMessage < ResponseMessage - def root_folder - return @root_folder if @root_folder + class FindItemResponseMessage < ResponseMessage + def root_folder + return @root_folder if @root_folder - rf = safe_hash_access message, %i[elems root_folder] - @root_folder = rf.nil? ? nil : RootFolder.new(rf) + rf = safe_hash_access message, %i[elems root_folder] + @root_folder = rf.nil? ? nil : RootFolder.new(rf) + end + end end end end diff --git a/lib/ews/soap/responses/get_events_response_message.rb b/lib/ews/soap/responses/get_events_response_message.rb index c0f5b7ba..5782072e 100644 --- a/lib/ews/soap/responses/get_events_response_message.rb +++ b/lib/ews/soap/responses/get_events_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,34 +16,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class GetEventsResponseMessage < ResponseMessage - def notification - safe_hash_access message, %i[elems notification elems] - end +module Viewpoint + module EWS + module SOAP + class GetEventsResponseMessage < ResponseMessage + def notification + safe_hash_access message, %i[elems notification elems] + end - def subscription_id - safe_hash_access notification[0], %i[subscription_id text] - end + def subscription_id + safe_hash_access notification[0], %i[subscription_id text] + end - def previous_watermark - safe_hash_access notification[1], %i[previous_watermark text] - end + def previous_watermark + safe_hash_access notification[1], %i[previous_watermark text] + end - def new_watermark - ev = notification.last - return unless ev + def new_watermark + ev = notification.last + return unless ev - type = ev.keys.first - ev[type][:elems][0][:watermark][:text] - end + type = ev.keys.first + ev[type][:elems][0][:watermark][:text] + end - def more_events? - safe_hash_access(notification[2], %i[more_events text]) == 'true' - end + def more_events? + safe_hash_access(notification[2], %i[more_events text]) == 'true' + end - def events - notification[3..-1] + def events + notification[3..-1] + end + end end end end diff --git a/lib/ews/soap/responses/send_notification_response_message.rb b/lib/ews/soap/responses/send_notification_response_message.rb index 83fe909f..33bcb1f7 100644 --- a/lib/ews/soap/responses/send_notification_response_message.rb +++ b/lib/ews/soap/responses/send_notification_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,41 +16,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class SendNotificationResponseMessage < ResponseMessage - include Viewpoint::StringUtils - - def notification - safe_hash_access message, %i[elems notification elems] - end - - def subscription_id - safe_hash_access notification[0], %i[subscription_id text] - end +module Viewpoint + module EWS + module SOAP + class SendNotificationResponseMessage < ResponseMessage + include Viewpoint::StringUtils - def previous_watermark - safe_hash_access notification[1], %i[previous_watermark text] - end + def notification + safe_hash_access message, %i[elems notification elems] + end - def new_watermark - ev = notification.last - return unless ev + def subscription_id + safe_hash_access notification[0], %i[subscription_id text] + end - type = ev.keys.first - ev[type][:elems][0][:watermark][:text] - end + def previous_watermark + safe_hash_access notification[1], %i[previous_watermark text] + end - def more_events? - safe_hash_access(notification[2], %i[more_events text]) == 'true' - end + def new_watermark + ev = notification.last + return unless ev - def events - @events ||= - notification[3..-1].collect { |ev| type = ev.keys.first - klass = Viewpoint::EWS::Types.const_get(camel_case(type)) - klass.new(nil, ev[type]) - } + ev[type][:elems][0][:watermark][:text] + end + + def more_events? + safe_hash_access(notification[2], %i[more_events text]) == 'true' + end + + def events + @events ||= + notification[3..-1].collect { |ev| + type = ev.keys.first + klass = Viewpoint::EWS::Types.const_get(camel_case(type)) + klass.new(nil, ev[type]) + } + end + end end end end diff --git a/lib/ews/soap/responses/subscribe_response_message.rb b/lib/ews/soap/responses/subscribe_response_message.rb index f0987702..44af48a6 100644 --- a/lib/ews/soap/responses/subscribe_response_message.rb +++ b/lib/ews/soap/responses/subscribe_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,18 +16,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class SubscribeResponseMessage < ResponseMessage - def subscription - safe_hash_access message, [:elems] - end +module Viewpoint + module EWS + module SOAP + class SubscribeResponseMessage < ResponseMessage + def subscription + safe_hash_access message, [:elems] + end - def subscription_id - safe_hash_access subscription, %i[subscription_id text] - end + def subscription_id + safe_hash_access subscription, %i[subscription_id text] + end - def watermark - safe_hash_access subscription, %i[watermark text] + def watermark + safe_hash_access subscription, %i[watermark text] + end + end end end end diff --git a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb index 653a369a..f79a8156 100644 --- a/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,19 +16,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class SyncFolderHierarchyResponseMessage < ResponseMessage - def sync_state - safe_hash_access message, %i[elems sync_state text] - end +module Viewpoint + module EWS + module SOAP + class SyncFolderHierarchyResponseMessage < ResponseMessage + def sync_state + safe_hash_access message, %i[elems sync_state text] + end - def includes_last_folder_in_range? - ans = safe_hash_access message, %i[elems includes_last_folder_in_range text] - ans.downcase == 'true' - end + def includes_last_folder_in_range? + ans = safe_hash_access message, %i[elems includes_last_folder_in_range text] + ans.downcase == 'true' + end - def changes - safe_hash_access(message, %i[elems changes elems]) || [] + def changes + safe_hash_access(message, %i[elems changes elems]) || [] + end + end end end end diff --git a/lib/ews/soap/responses/sync_folder_items_response_message.rb b/lib/ews/soap/responses/sync_folder_items_response_message.rb index 2b4a5de0..4aa226d6 100644 --- a/lib/ews/soap/responses/sync_folder_items_response_message.rb +++ b/lib/ews/soap/responses/sync_folder_items_response_message.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,19 +16,23 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::SOAP - class SyncFolderItemsResponseMessage < ResponseMessage - def sync_state - safe_hash_access message, %i[elems sync_state text] - end +module Viewpoint + module EWS + module SOAP + class SyncFolderItemsResponseMessage < ResponseMessage + def sync_state + safe_hash_access message, %i[elems sync_state text] + end - def includes_last_item_in_range? - ans = safe_hash_access message, %i[elems includes_last_item_in_range text] - ans.downcase == 'true' - end + def includes_last_item_in_range? + ans = safe_hash_access message, %i[elems includes_last_item_in_range text] + ans.downcase == 'true' + end - def changes - safe_hash_access(message, %i[elems changes elems]) || [] + def changes + safe_hash_access(message, %i[elems changes elems]) || [] + end + end end end end diff --git a/lib/ews/templates/calendar_item.rb b/lib/ews/templates/calendar_item.rb index ddf09dfa..9ea2e311 100644 --- a/lib/ews/templates/calendar_item.rb +++ b/lib/ews/templates/calendar_item.rb @@ -1,76 +1,79 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Template - # Template for creating CalendarItems - # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx - class CalendarItem < OpenStruct - # Available parameters with the required ordering - PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments - date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend is_unmodified - internet_message_headers date_time_sent date_time_created response_objects reminder_due_by reminder_is_set - reminder_minutes_before_start display_cc display_to has_attachments extended_property culture start end - original_start is_all_day_event legacy_free_busy_status location when is_meeting is_cancelled is_recurring - meeting_request_was_sent is_response_requested calendar_item_type my_response_type organizer - required_attendees optional_attendees resources conflicting_meeting_count adjacent_meeting_count - conflicting_meetings adjacent_meetings duration time_zone appointment_reply_time appointment_sequence_number - appointment_state recurrence first_occurrence last_occurrence modified_occurrences deleted_occurrences - meeting_time_zone start_time_zone end_time_zone conference_type allow_new_time_proposal is_online_meeting - meeting_workspace_url net_show_url effective_rights last_modified_name last_modified_time is_associated - web_client_read_form_query_string web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze - # Returns a new CalendarItem template - def initialize(opts = {}) - super opts.dup - end +module Viewpoint + module EWS + module Template + # Template for creating CalendarItems + # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx + class CalendarItem < OpenStruct + # Available parameters with the required ordering + PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments + date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend is_unmodified + internet_message_headers date_time_sent date_time_created response_objects reminder_due_by reminder_is_set + reminder_minutes_before_start display_cc display_to has_attachments extended_property culture start end + original_start is_all_day_event legacy_free_busy_status location when is_meeting is_cancelled is_recurring + meeting_request_was_sent is_response_requested calendar_item_type my_response_type organizer + required_attendees optional_attendees resources conflicting_meeting_count adjacent_meeting_count + conflicting_meetings adjacent_meetings duration time_zone appointment_reply_time appointment_sequence_number + appointment_state recurrence first_occurrence last_occurrence modified_occurrences deleted_occurrences + meeting_time_zone start_time_zone end_time_zone conference_type allow_new_time_proposal is_online_meeting + meeting_workspace_url net_show_url effective_rights last_modified_name last_modified_time is_associated + web_client_read_form_query_string web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze + + # Returns a new CalendarItem template + def initialize(opts = {}) + super opts.dup + end - # EWS CreateItem container - # @return [Hash] - def to_ews_create(opts = {}) - structure = {} - structure[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') - # options - structure[:send_meeting_invitations] = - (opts.has_key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') + # EWS CreateItem container + # @return [Hash] + def to_ews_create(opts = {}) + structure = {} + structure[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') + # options + structure[:send_meeting_invitations] = + (opts.has_key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') - if saved_item_folder_id - structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) - saved_item_folder_id - else - { id: saved_item_folder_id } - end + if saved_item_folder_id + structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end + end + + structure[:items] = [{ calendar_item: to_ews_item }] + structure end - structure[:items] = [{ calendar_item: to_ews_item }] - structure - end + # EWS Item hash + # + # Puts all known parameters in the required ordering and structure + # @return [Hash] + def to_ews_item + item_parameters = {} + PARAMETERS.each do |key| + next if (value = send(key)).nil? - # EWS Item hash - # - # Puts all known parameters in the required ordering and structure - # @return [Hash] - def to_ews_item - item_parameters = {} - PARAMETERS.each do |key| - next if (value = send(key)).nil? + # Convert non duplicable values to String + case value + when NilClass, FalseClass, TrueClass, Symbol, Numeric + value = value.to_s + end - # Convert non duplicable values to String - case value - when NilClass, FalseClass, TrueClass, Symbol, Numeric - value = value.to_s + # Convert attributes + item_parameters[key] = case key + when :start, :end + { text: value.respond_to?(:iso8601) ? value.iso8601 : value } + when :body + { body_type: body_type || 'Text', text: value.to_s } + else + value + end end - # Convert attributes - item_parameters[key] = case key - when :start, :end - { text: value.respond_to?(:iso8601) ? value.iso8601 : value } - when :body - { body_type: body_type || 'Text', text: value.to_s } - else - value - end + item_parameters end - - item_parameters end end end diff --git a/lib/ews/templates/forward_item.rb b/lib/ews/templates/forward_item.rb index edba1379..484d093a 100644 --- a/lib/ews/templates/forward_item.rb +++ b/lib/ews/templates/forward_item.rb @@ -1,21 +1,24 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Template - class ForwardItem < Message - # Format this object for EWS backend consumption. - def to_ews - ews_opts, msg = to_ews_basic - msg[:reference_item_id] = reference_item_id - msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } - ews_opts.merge({ items: [{ forward_item: msg }] }) - end - private +module Viewpoint + module EWS + module Template + class ForwardItem < Message + # Format this object for EWS backend consumption. + def to_ews + ews_opts, msg = to_ews_basic + msg[:reference_item_id] = reference_item_id + msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } + ews_opts.merge({ items: [{ forward_item: msg }] }) + end + + private - def init_defaults! - super - self.new_body_content ||= '' - self.new_body_type ||= 'Text' + def init_defaults! + super + self.new_body_content ||= '' + self.new_body_type ||= 'Text' + end end end end diff --git a/lib/ews/templates/message.rb b/lib/ews/templates/message.rb index 135e331e..0c429e97 100644 --- a/lib/ews/templates/message.rb +++ b/lib/ews/templates/message.rb @@ -1,72 +1,75 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Template - class Message < OpenStruct - def initialize(opts = {}) - super opts.clone - init_defaults! - end - - # Format this object for EWS backend consumption. - def to_ews - ews_opts, msg = to_ews_basic - ews_opts.merge({ items: [{ message: msg }] }) - end - def has_attachments? - !(file_attachments.empty? && item_attachments.empty? && inline_attachments.empty?) - end +module Viewpoint + module EWS + module Template + class Message < OpenStruct + def initialize(opts = {}) + super opts.clone + init_defaults! + end - private + # Format this object for EWS backend consumption. + def to_ews + ews_opts, msg = to_ews_basic + ews_opts.merge({ items: [{ message: msg }] }) + end - def init_defaults! - self.subject ||= nil - self.body ||= nil - self.body_type ||= 'Text' - self.importance ||= 'Normal' - self.draft ||= false - self.is_read = true if is_read.nil? - self.to_recipients ||= [] - self.cc_recipients ||= [] - self.bcc_recipients ||= [] - self.file_attachments ||= [] - self.item_attachments ||= [] - self.inline_attachments ||= [] - self.extended_properties ||= [] - end + def has_attachments? + !(file_attachments.empty? && item_attachments.empty? && inline_attachments.empty?) + end - def to_ews_basic - ews_opts = {} - ews_opts[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') + private - if saved_item_folder_id - ews_opts[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) - saved_item_folder_id - else - { id: saved_item_folder_id } - end + def init_defaults! + self.subject ||= nil + self.body ||= nil + self.body_type ||= 'Text' + self.importance ||= 'Normal' + self.draft ||= false + self.is_read = true if is_read.nil? + self.to_recipients ||= [] + self.cc_recipients ||= [] + self.bcc_recipients ||= [] + self.file_attachments ||= [] + self.item_attachments ||= [] + self.inline_attachments ||= [] + self.extended_properties ||= [] end - msg = {} - msg[:subject] = subject if subject - msg[:body] = { text: body, body_type: body_type } if body + def to_ews_basic + ews_opts = {} + ews_opts[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') + + if saved_item_folder_id + ews_opts[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end + end - msg[:importance] = importance if importance + msg = {} + msg[:subject] = subject if subject + msg[:body] = { text: body, body_type: body_type } if body - to_r = to_recipients.collect { |r| { mailbox: { email_address: r } } } - msg[:to_recipients] = to_r unless to_r.empty? + msg[:importance] = importance if importance - cc_r = cc_recipients.collect { |r| { mailbox: { email_address: r } } } - msg[:cc_recipients] = cc_r unless cc_r.empty? + to_r = to_recipients.collect { |r| { mailbox: { email_address: r } } } + msg[:to_recipients] = to_r unless to_r.empty? - bcc_r = bcc_recipients.collect { |r| { mailbox: { email_address: r } } } - msg[:bcc_recipients] = bcc_r unless bcc_r.empty? + cc_r = cc_recipients.collect { |r| { mailbox: { email_address: r } } } + msg[:cc_recipients] = cc_r unless cc_r.empty? - msg[:is_read] = is_read + bcc_r = bcc_recipients.collect { |r| { mailbox: { email_address: r } } } + msg[:bcc_recipients] = bcc_r unless bcc_r.empty? - msg[:extended_properties] = extended_properties unless extended_properties.empty? + msg[:is_read] = is_read - [ews_opts, msg] + msg[:extended_properties] = extended_properties unless extended_properties.empty? + + [ews_opts, msg] + end end end end diff --git a/lib/ews/templates/reply_to_item.rb b/lib/ews/templates/reply_to_item.rb index 388d5131..70aecc39 100644 --- a/lib/ews/templates/reply_to_item.rb +++ b/lib/ews/templates/reply_to_item.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Template - class ReplyToItem < Message - # Format this object for EWS backend consumption. - def to_ews - ews_opts, msg = to_ews_basic - msg[:reference_item_id] = reference_item_id - msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } - ews_opts.merge({ items: [{ ews_type => msg }] }) - end - private +module Viewpoint + module EWS + module Template + class ReplyToItem < Message + # Format this object for EWS backend consumption. + def to_ews + ews_opts, msg = to_ews_basic + msg[:reference_item_id] = reference_item_id + msg[:new_body_content] = { text: new_body_content, body_type: new_body_type } + ews_opts.merge({ items: [{ ews_type => msg }] }) + end + + private - def init_defaults! - super - self.new_body_content ||= '' - self.new_body_type ||= 'Text' - self.ews_type = :reply_to_item + def init_defaults! + super + self.new_body_content ||= '' + self.new_body_type ||= 'Text' + self.ews_type = :reply_to_item + end end end end diff --git a/lib/ews/templates/task.rb b/lib/ews/templates/task.rb index a16e5f65..41a74e07 100644 --- a/lib/ews/templates/task.rb +++ b/lib/ews/templates/task.rb @@ -1,70 +1,73 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Template - # Template for creating Tasks - # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx - class Task < OpenStruct - # Available parameters with the required ordering - PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments - date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend - is_unmodified internet_message_headers date_time_sent date_time_created response_objects - reminder_due_by reminder_is_set reminder_minutes_before_start display_cc display_to - has_attachments extended_property culture actual_work assigned_time billing_information - change_count companies complete_date contacts delegation_state delegator due_date - is_assignment_editable is_complete is_recurring is_team_task mileage owner percent_complete - recurrence start_date status status_description total_work effective_rights last_modified_name - last_modified_time is_associated web_client_read_form_query_string - web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze - # Returns a new Task template - def initialize(opts = {}) - super opts.dup - end +module Viewpoint + module EWS + module Template + # Template for creating Tasks + # @see http://msdn.microsoft.com/en-us/library/exchange/aa564765.aspx + class Task < OpenStruct + # Available parameters with the required ordering + PARAMETERS = %w[mime_content item_id parent_folder_id item_class subject sensitivity body attachments + date_time_received size categories in_reply_to is_submitted is_draft is_from_me is_resend + is_unmodified internet_message_headers date_time_sent date_time_created response_objects + reminder_due_by reminder_is_set reminder_minutes_before_start display_cc display_to + has_attachments extended_property culture actual_work assigned_time billing_information + change_count companies complete_date contacts delegation_state delegator due_date + is_assignment_editable is_complete is_recurring is_team_task mileage owner percent_complete + recurrence start_date status status_description total_work effective_rights last_modified_name + last_modified_time is_associated web_client_read_form_query_string + web_client_edit_form_query_string conversation_id unique_body].map(&:to_sym).freeze + + # Returns a new Task template + def initialize(opts = {}) + super opts.dup + end - # EWS CreateItem container - # @return [Hash] - def to_ews_create - structure = {} + # EWS CreateItem container + # @return [Hash] + def to_ews_create + structure = {} - if saved_item_folder_id - structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) - saved_item_folder_id - else - { id: saved_item_folder_id } - end + if saved_item_folder_id + structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) + saved_item_folder_id + else + { id: saved_item_folder_id } + end + end + + structure[:items] = [{ task: to_ews_item }] + structure end - structure[:items] = [{ task: to_ews_item }] - structure - end + # EWS Item hash + # + # Puts all known parameters in the required ordering and structure + # @return [Hash] + def to_ews_item + item_parameters = {} + PARAMETERS.each do |key| + next if (value = send(key)).nil? - # EWS Item hash - # - # Puts all known parameters in the required ordering and structure - # @return [Hash] - def to_ews_item - item_parameters = {} - PARAMETERS.each do |key| - next if (value = send(key)).nil? + # Convert non duplicable values to String + case value + when NilClass, FalseClass, TrueClass, Symbol, Numeric + value = value.to_s + end - # Convert non duplicable values to String - case value - when NilClass, FalseClass, TrueClass, Symbol, Numeric - value = value.to_s + # Convert attributes + item_parameters[key] = case key + when :start_date, :due_date + { text: value.respond_to?(:iso8601) ? value.iso8601 : value } + when :body + { body_type: body_type || 'Text', text: value.to_s } + else + value + end end - # Convert attributes - item_parameters[key] = case key - when :start_date, :due_date - { text: value.respond_to?(:iso8601) ? value.iso8601 : value } - when :body - { body_type: body_type || 'Text', text: value.to_s } - else - value - end + item_parameters end - - item_parameters end end end diff --git a/lib/ews/types.rb b/lib/ews/types.rb index 5d6cbd58..2ea2c791 100644 --- a/lib/ews/types.rb +++ b/lib/ews/types.rb @@ -1,177 +1,180 @@ # frozen_string_literal: true -module Viewpoint::EWS - module Types - include Viewpoint::StringUtils - - KEY_PATHS = { - extended_properties: [:extended_property] - } - KEY_TYPES = { - extended_properties: :build_extended_properties - } - KEY_ALIAS = {} - - attr_reader :ews_item - - # @param [SOAP::ExchangeWebService] ews the EWS reference - # @param [Hash] ews_item the EWS parsed response document - def initialize(ews, ews_item) - @ews = ews - @ews_item = ews_item - @shallow = true - @frozen = false - end - def method_missing(method_sym, *arguments, &block) - if method_keys.include?(method_sym) - type_convert(method_sym, resolve_method(method_sym)) - else - super +module Viewpoint + module EWS + module Types + include Viewpoint::StringUtils + + KEY_PATHS = { + extended_properties: [:extended_property] + } + KEY_TYPES = { + extended_properties: :build_extended_properties + } + KEY_ALIAS = {} + + attr_reader :ews_item + + # @param [SOAP::ExchangeWebService] ews the EWS reference + # @param [Hash] ews_item the EWS parsed response document + def initialize(ews, ews_item) + @ews = ews + @ews_item = ews_item + @shallow = true + @frozen = false end - end - def to_s - "#{self.class.name}: EWS METHODS: #{ews_methods.sort.join(', ')}" - end + def method_missing(method_sym, *arguments, &block) + if method_keys.include?(method_sym) + type_convert(method_sym, resolve_method(method_sym)) + else + super + end + end - def frozen? - @frozen - end + def to_s + "#{self.class.name}: EWS METHODS: #{ews_methods.sort.join(', ')}" + end - # @param ronly [Boolean] true to freeze - def freeze! - @frozen = true - end + def frozen? + @frozen + end - def unfreeze! - @frozen = false - end + # @param ronly [Boolean] true to freeze + def freeze! + @frozen = true + end - def shallow? - @shallow - end + def unfreeze! + @frozen = false + end - def mark_deep! - @shallow = false - end + def shallow? + @shallow + end - def auto_deepen? - ews.auto_deepen - end + def mark_deep! + @shallow = false + end - def deepen! - return unless shallow? + def auto_deepen? + ews.auto_deepen + end - get_all_properties! - @shallow = false - true - end - alias enlighten! deepen! + def deepen! + return unless shallow? - # @see http://www.ruby-doc.org/core/classes/Object.html#M000333 - def respond_to?(method_sym, include_private = false) - method_keys.include?(method_sym) || super - end + get_all_properties! + @shallow = false + true + end + alias enlighten! deepen! - def methods(include_super = true) - super + ews_methods - end + # @see http://www.ruby-doc.org/core/classes/Object.html#M000333 + def respond_to?(method_sym, include_private = false) + method_keys.include?(method_sym) || super + end - def ews_methods - key_paths.keys + key_alias.keys - end + def methods(include_super = true) + super + ews_methods + end - protected # things like OutOfOffice need protected level access + def ews_methods + key_paths.keys + key_alias.keys + end - def ews - @ews - end + protected # things like OutOfOffice need protected level access - private + def ews + @ews + end - def key_paths - KEY_PATHS - end + private - def key_types - KEY_TYPES - end + def key_paths + KEY_PATHS + end - def key_alias - KEY_ALIAS - end + def key_types + KEY_TYPES + end - def class_by_name(cname) - cname = camel_case(cname) if cname.instance_of? Symbol - Viewpoint::EWS::Types.const_get(cname) - end + def key_alias + KEY_ALIAS + end - def type_convert(key, str) - key = key_alias[key] || key - if key_types[key] - key_types[key].is_a?(Symbol) ? method(key_types[key]).call(str) : key_types[key].call(str) - else - str + def class_by_name(cname) + cname = camel_case(cname) if cname.instance_of? Symbol + Viewpoint::EWS::Types.const_get(cname) end - rescue StandardError - nil - end - def resolve_method(method_sym) - resolve_key_path(@ews_item, method_path(method_sym)) - rescue StandardError - if shallow? - if frozen? - raise EwsFrozenObjectError, "Could not resolve :#{method_sym} on frozen object." - elsif auto_deepen? - enlighten! - retry - elsif !auto_deepen? && (ews.no_auto_deepen_behavior == :raise) - raise EwsMinimalObjectError, "Could not resolve :#{method_sym}. #auto_deepen set to false" + def type_convert(key, str) + key = key_alias[key] || key + if key_types[key] + key_types[key].is_a?(Symbol) ? method(key_types[key]).call(str) : key_types[key].call(str) + else + str + end + rescue StandardError + nil + end + + def resolve_method(method_sym) + resolve_key_path(@ews_item, method_path(method_sym)) + rescue StandardError + if shallow? + if frozen? + raise EwsFrozenObjectError, "Could not resolve :#{method_sym} on frozen object." + elsif auto_deepen? + enlighten! + retry + elsif !auto_deepen? && (ews.no_auto_deepen_behavior == :raise) + raise EwsMinimalObjectError, "Could not resolve :#{method_sym}. #auto_deepen set to false" + end end end - end - def resolve_key_path(hsh, path) - k = path.first - return hsh[k] if path.length == 1 + def resolve_key_path(hsh, path) + k = path.first + return hsh[k] if path.length == 1 - resolve_key_path(hsh[k], path[1..-1]) - end + resolve_key_path(hsh[k], path[1..-1]) + end - def method_keys - key_paths.keys + key_alias.keys - end + def method_keys + key_paths.keys + key_alias.keys + end - # Resolve the method path with or without an alias - def method_path(sym) - key_paths[key_alias[sym] || sym] - end + # Resolve the method path with or without an alias + def method_path(sym) + key_paths[key_alias[sym] || sym] + end - def build_extended_properties(eprops) - h = {} - # todo - # the return pattern seems broken in some cases, - # probably needs fixing via a dedicated response parser - eprops.each do |e| - if e.size == 1 - e[:elems].each_cons(2) do |k, v| - key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym - val = v[:value][:text] - h.store(key, val) - end - elsif e.size == 2 - e[1].each_cons(2) do |k, v| - key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym - val = v[:value][:text] - h.store(key, val) + def build_extended_properties(eprops) + h = {} + # todo + # the return pattern seems broken in some cases, + # probably needs fixing via a dedicated response parser + eprops.each do |e| + if e.size == 1 + e[:elems].each_cons(2) do |k, v| + key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym + val = v[:value][:text] + h.store(key, val) + end + elsif e.size == 2 + e[1].each_cons(2) do |k, v| + key = k[:extended_field_u_r_i][:attribs][:property_name].downcase.to_sym + val = v[:value][:text] + h.store(key, val) + end + else + raise EwsMinimalObjectError, 'Not prepared to deal with elements greater than 2' end - else - raise EwsMinimalObjectError, 'Not prepared to deal with elements greater than 2' end + h end - h end end end diff --git a/lib/ews/types/attachment.rb b/lib/ews/types/attachment.rb index 042f9fc6..69d9f344 100644 --- a/lib/ews/types/attachment.rb +++ b/lib/ews/types/attachment.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,59 +16,63 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - # A generic Attachment. This class should not be instantiated directly. You - # should use one of the subclasses like FileAttachment or ItemAttachment. - class Attachment - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item +module Viewpoint + module EWS + module Types + # A generic Attachment. This class should not be instantiated directly. You + # should use one of the subclasses like FileAttachment or ItemAttachment. + class Attachment + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item - ATTACH_KEY_PATHS = { - id: %i[attachment_id attribs id], - parent_item_id: %i[attachment_id attribs root_item_id], - parent_change_key: %i[attachment_id attribs root_item_change_key], - name: %i[name text], - content_type: %i[content_type text], - content_id: [:content_id], - size: %i[size text], - last_modified_time: %i[last_modified_time text], - is_inline?: %i[is_inline text] - } + ATTACH_KEY_PATHS = { + id: %i[attachment_id attribs id], + parent_item_id: %i[attachment_id attribs root_item_id], + parent_change_key: %i[attachment_id attribs root_item_change_key], + name: %i[name text], + content_type: %i[content_type text], + content_id: [:content_id], + size: %i[size text], + last_modified_time: %i[last_modified_time text], + is_inline?: %i[is_inline text] + } - ATTACH_KEY_TYPES = { - is_inline?: ->(str) { str.downcase == 'true' }, - last_modified_type: ->(str) { DateTime.parse(str) }, - size: ->(str) { str.to_i }, - content_id: :fix_content_id - } + ATTACH_KEY_TYPES = { + is_inline?: ->(str) { str.downcase == 'true' }, + last_modified_type: ->(str) { DateTime.parse(str) }, + size: ->(str) { str.to_i }, + content_id: :fix_content_id + } - ATTACH_KEY_ALIAS = {} + ATTACH_KEY_ALIAS = {} - # @param [Hash] attachment The attachment ews_item - def initialize(item, attachment) - @item = item - super(item.ews, attachment) - end + # @param [Hash] attachment The attachment ews_item + def initialize(item, attachment) + @item = item + super(item.ews, attachment) + end - private + private - def key_paths - @key_paths ||= ATTACH_KEY_PATHS - end + def key_paths + @key_paths ||= ATTACH_KEY_PATHS + end - def key_types - @key_types ||= ATTACH_KEY_TYPES - end + def key_types + @key_types ||= ATTACH_KEY_TYPES + end - def key_alias - @key_alias ||= ATTACH_KEY_ALIAS - end + def key_alias + @key_alias ||= ATTACH_KEY_ALIAS + end - # Sometimes the SOAP response comes back with two identical content_ids. - # This method fishes them out no matter which way them come. - def fix_content_id(content_id) - content_id.is_a?(Array) ? content_id.last[:text] : content_id[:text] + # Sometimes the SOAP response comes back with two identical content_ids. + # This method fishes them out no matter which way them come. + def fix_content_id(content_id) + content_id.is_a?(Array) ? content_id.last[:text] : content_id[:text] + end + end end end end diff --git a/lib/ews/types/attendee.rb b/lib/ews/types/attendee.rb index 09a8e27c..422c717b 100644 --- a/lib/ews/types/attendee.rb +++ b/lib/ews/types/attendee.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,10 +16,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - # This represents a Mailbox object in the Exchange data store - # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs - # @todo Design a Class method that resolves to an Array of MailboxUsers - class Attendee < MailboxUser +module Viewpoint + module EWS + module Types + # This represents a Mailbox object in the Exchange data store + # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs + # @todo Design a Class method that resolves to an Array of MailboxUsers + class Attendee < MailboxUser + end + end end end diff --git a/lib/ews/types/calendar_folder.rb b/lib/ews/types/calendar_folder.rb index e3bede33..bc5f1a50 100644 --- a/lib/ews/types/calendar_folder.rb +++ b/lib/ews/types/calendar_folder.rb @@ -1,59 +1,64 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class CalendarFolder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::GenericFolder - # Fetch items between a given time period - # @param [DateTime] start_date the time to start fetching Items from - # @param [DateTime] end_date the time to stop fetching Items from - def items_between(start_date, end_date, _opts = {}) - items do |obj| - obj.restriction = { and: [ - { is_greater_than_or_equal_to: [ - { field_uRI: { field_uRI: 'calendar:Start' } }, - { field_uRI_or_constant: { constant: { value: start_date } } } - ] }, - { is_less_than_or_equal_to: [ - { field_uRI: { field_uRI: 'calendar:End' } }, - { field_uRI_or_constant: { constant: { value: end_date } } } - ] } - ] } - end - end +module Viewpoint + module EWS + module Types + class CalendarFolder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::GenericFolder - # Fetch items between a given time period using a calendar view. - # The calendar view will include occurences of recurring calendar items - # next to the regular single calendar items. - # @param [DateTime] start_date the time to start fetching Items from - # @param [DateTime] end_date the time to stop fetching Items from - # @param opts [Hash] - # @option opts :max_entries_returned [Integer] the maximum number of entries to return - def items_between_calendar_view(start_date, end_date, opts = {}) - view_opts = { start_date: start_date, end_date: end_date } - view_opts[:max_entries_returned] = opts.delete(:max_entries_returned) if opts[:max_entries_returned] - items(opts.merge(calendar_view: view_opts)) - end + # Fetch items between a given time period + # @param [DateTime] start_date the time to start fetching Items from + # @param [DateTime] end_date the time to stop fetching Items from + def items_between(start_date, end_date, _opts = {}) + items do |obj| + obj.restriction = { and: [ + { is_greater_than_or_equal_to: [ + { field_uRI: { field_uRI: 'calendar:Start' } }, + { field_uRI_or_constant: { constant: { value: start_date } } } + ] }, + { is_less_than_or_equal_to: [ + { field_uRI: { field_uRI: 'calendar:End' } }, + { field_uRI_or_constant: { constant: { value: end_date } } } + ] } + ] } + end + end + + # Fetch items between a given time period using a calendar view. + # The calendar view will include occurences of recurring calendar items + # next to the regular single calendar items. + # @param [DateTime] start_date the time to start fetching Items from + # @param [DateTime] end_date the time to stop fetching Items from + # @param opts [Hash] + # @option opts :max_entries_returned [Integer] the maximum number of entries to return + def items_between_calendar_view(start_date, end_date, opts = {}) + view_opts = { start_date: start_date, end_date: end_date } + view_opts[:max_entries_returned] = opts.delete(:max_entries_returned) if opts[:max_entries_returned] + items(opts.merge(calendar_view: view_opts)) + end - # Creates a new appointment - # @param attributes [Hash] Parameters of the calendar item. Some example attributes are listed below. - # @option attributes :subject [String] - # @option attributes :start [Time] - # @option attributes :end [Time] - # @return [CalendarItem] - # @see Template::CalendarItem - def create_item(attributes, to_ews_create_opts = {}) - template = Viewpoint::EWS::Template::CalendarItem.new attributes - template.saved_item_folder_id = { id: id, change_key: change_key } - rm = ews.create_item(template.to_ews_create(to_ews_create_opts)).response_messages.first - if rm && rm.success? - CalendarItem.new ews, rm.items.first[:calendar_item][:elems].first - else - raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm + # Creates a new appointment + # @param attributes [Hash] Parameters of the calendar item. Some example attributes are listed below. + # @option attributes :subject [String] + # @option attributes :start [Time] + # @option attributes :end [Time] + # @return [CalendarItem] + # @see Template::CalendarItem + def create_item(attributes, to_ews_create_opts = {}) + template = Viewpoint::EWS::Template::CalendarItem.new attributes + template.saved_item_folder_id = { id: id, change_key: change_key } + rm = ews.create_item(template.to_ews_create(to_ews_create_opts)).response_messages.first + if rm && rm.success? + CalendarItem.new ews, rm.items.first[:calendar_item][:elems].first + else + raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm - raise EwsCreateItemError, 'Could not create item in folder.' + raise EwsCreateItemError, 'Could not create item in folder.' + end + end end end end diff --git a/lib/ews/types/calendar_item.rb b/lib/ews/types/calendar_item.rb index 47672deb..6e209cd6 100644 --- a/lib/ews/types/calendar_item.rb +++ b/lib/ews/types/calendar_item.rb @@ -1,142 +1,147 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class CalendarItem - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item - include Viewpoint::StringUtils - - CALENDAR_ITEM_KEY_PATHS = { - recurring?: %i[is_recurring text], - meeting?: %i[is_meeting text], - cancelled?: %i[is_cancelled text], - duration: %i[duration text], - time_zone: %i[time_zone text], - start: %i[start text], - end: %i[end text], - location: %i[location text], - all_day?: %i[is_all_day_event text], - legacy_free_busy_status: %i[legacy_free_busy_status text], - my_response_type: %i[my_response_type text], - organizer: [:organizer, :elems, 0, :mailbox, :elems], - optional_attendees: %i[optional_attendees elems], - required_attendees: %i[required_attendees elems], - recurrence: %i[recurrence elems], - deleted_occurrences: %i[deleted_occurrences elems], - modified_occurrences: %i[modified_occurrences elems] - } - - CALENDAR_ITEM_KEY_TYPES = { - start: ->(str) { DateTime.parse(str) }, - end: ->(str) { DateTime.parse(str) }, - recurring?: ->(str) { str.downcase == 'true' }, - meeting?: ->(str) { str.downcase == 'true' }, - cancelled?: ->(str) { str.downcase == 'true' }, - all_day?: ->(str) { str.downcase == 'true' }, - organizer: :build_mailbox_user, - optional_attendees: :build_attendees_users, - required_attendees: :build_attendees_users, - deleted_occurrences: :build_deleted_occurrences, - modified_occurrences: :build_modified_occurrences - } - CALENDAR_ITEM_KEY_ALIAS = {} - - # Delete this calendar item - # @param deltype [Symbol] The delete type; must be :hard, :soft, or :recycle. - # By default EWS will do a hard delete of this calendar item. See the= - # MSDN docs for more info: http://msdn.microsoft.com/en-us/library/aa562961.aspx - # @param cancel_type [String] 'SendToNone'/'SendOnlyToAll'/'SendToAllAndSaveCopy' - # Default is 'SendOnlyToAll' - # @return [Boolean] Whether or not the calendar item was deleted - def delete!(deltype = :hard, cancel_type = 'SendOnlyToAll', opts = {}) - opts = opts.merge(send_meeting_cancellations: cancel_type) - super(deltype, opts) - end - # Updates the specified item attributes - # - # Uses `SetItemField` if value is present and `DeleteItemField` if value is nil - # @param updates [Hash] with (:attribute => value) - # @param options [Hash] - # @option options :conflict_resolution [String] one of 'NeverOverwrite', 'AutoResolve' (default) or 'AlwaysOverwrite' - # @option options :send_meeting_invitations_or_cancellations [String] one of 'SendToNone' (default), 'SendOnlyToAll', - # 'SendOnlyToChanged', 'SendToAllAndSaveCopy' or 'SendToChangedAndSaveCopy' - # @return [CalendarItem, false] - # @example Update Subject and Body - # item = #... - # item.update_item!(subject: 'New subject', body: 'New Body') - # @see http://msdn.microsoft.com/en-us/library/exchange/aa580254.aspx - # @todo AppendToItemField updates not implemented - def update_item!(updates, options = {}) - item_updates = [] - updates.each do |attribute, value| - item_field = FIELD_URIS[attribute][:text] if FIELD_URIS.include? attribute - field = { field_uRI: { field_uRI: item_field } } - - if value.nil? && item_field - # Build DeleteItemField Change - item_updates << { delete_item_field: field } - elsif item_field - # Build SetItemField Change - item = Viewpoint::EWS::Template::CalendarItem.new(attribute => value) - - # Remap attributes because ews_builder #dispatch_field_item! uses #build_xml! - item_attributes = item.to_ews_item.map { |name, value| - if value.is_a? String - { name => { text: value } } - elsif value.is_a? Hash - node = { name => {} } - value.each do |attrib_key, attrib_value| - attrib_key = camel_case(attrib_key) unless attrib_key == :text - node[name][attrib_key] = attrib_value - end - node +module Viewpoint + module EWS + module Types + class CalendarItem + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + include Viewpoint::StringUtils + + CALENDAR_ITEM_KEY_PATHS = { + recurring?: %i[is_recurring text], + meeting?: %i[is_meeting text], + cancelled?: %i[is_cancelled text], + duration: %i[duration text], + time_zone: %i[time_zone text], + start: %i[start text], + end: %i[end text], + location: %i[location text], + all_day?: %i[is_all_day_event text], + legacy_free_busy_status: %i[legacy_free_busy_status text], + my_response_type: %i[my_response_type text], + organizer: [:organizer, :elems, 0, :mailbox, :elems], + optional_attendees: %i[optional_attendees elems], + required_attendees: %i[required_attendees elems], + recurrence: %i[recurrence elems], + deleted_occurrences: %i[deleted_occurrences elems], + modified_occurrences: %i[modified_occurrences elems] + } + + CALENDAR_ITEM_KEY_TYPES = { + start: ->(str) { DateTime.parse(str) }, + end: ->(str) { DateTime.parse(str) }, + recurring?: ->(str) { str.downcase == 'true' }, + meeting?: ->(str) { str.downcase == 'true' }, + cancelled?: ->(str) { str.downcase == 'true' }, + all_day?: ->(str) { str.downcase == 'true' }, + organizer: :build_mailbox_user, + optional_attendees: :build_attendees_users, + required_attendees: :build_attendees_users, + deleted_occurrences: :build_deleted_occurrences, + modified_occurrences: :build_modified_occurrences + } + CALENDAR_ITEM_KEY_ALIAS = {} + + # Delete this calendar item + # @param deltype [Symbol] The delete type; must be :hard, :soft, or :recycle. + # By default EWS will do a hard delete of this calendar item. See the= + # MSDN docs for more info: http://msdn.microsoft.com/en-us/library/aa562961.aspx + # @param cancel_type [String] 'SendToNone'/'SendOnlyToAll'/'SendToAllAndSaveCopy' + # Default is 'SendOnlyToAll' + # @return [Boolean] Whether or not the calendar item was deleted + def delete!(deltype = :hard, cancel_type = 'SendOnlyToAll', opts = {}) + opts = opts.merge(send_meeting_cancellations: cancel_type) + super(deltype, opts) + end + + # Updates the specified item attributes + # + # Uses `SetItemField` if value is present and `DeleteItemField` if value is nil + # @param updates [Hash] with (:attribute => value) + # @param options [Hash] + # @option options :conflict_resolution [String] one of 'NeverOverwrite', 'AutoResolve' (default) or 'AlwaysOverwrite' + # @option options :send_meeting_invitations_or_cancellations [String] one of 'SendToNone' (default), 'SendOnlyToAll', + # 'SendOnlyToChanged', 'SendToAllAndSaveCopy' or 'SendToChangedAndSaveCopy' + # @return [CalendarItem, false] + # @example Update Subject and Body + # item = #... + # item.update_item!(subject: 'New subject', body: 'New Body') + # @see http://msdn.microsoft.com/en-us/library/exchange/aa580254.aspx + # @todo AppendToItemField updates not implemented + def update_item!(updates, options = {}) + item_updates = [] + updates.each do |attribute, value| + item_field = FIELD_URIS[attribute][:text] if FIELD_URIS.include? attribute + field = { field_uRI: { field_uRI: item_field } } + + if value.nil? && item_field + # Build DeleteItemField Change + item_updates << { delete_item_field: field } + elsif item_field + # Build SetItemField Change + item = Viewpoint::EWS::Template::CalendarItem.new(attribute => value) + + # Remap attributes because ews_builder #dispatch_field_item! uses #build_xml! + item_attributes = item.to_ews_item.map { |name, value| + if value.is_a? String + { name => { text: value } } + elsif value.is_a? Hash + node = { name => {} } + value.each do |attrib_key, attrib_value| + attrib_key = camel_case(attrib_key) unless attrib_key == :text + node[name][attrib_key] = attrib_value + end + node + else + { name => value } + end + } + + item_updates << { set_item_field: field.merge(calendar_item: { sub_elements: item_attributes }) } else - { name => value } + # Ignore unknown attribute end - } + end - item_updates << { set_item_field: field.merge(calendar_item: { sub_elements: item_attributes }) } - else - # Ignore unknown attribute - end - end + return unless item_updates.any? - return unless item_updates.any? + data = {} + data[:conflict_resolution] = options[:conflict_resolution] || 'AutoResolve' + data[:send_meeting_invitations_or_cancellations] = + options[:send_meeting_invitations_or_cancellations] || 'SendToNone' + data[:item_changes] = [{ item_id: item_id, updates: item_updates }] + rm = ews.update_item(data).response_messages.first + if rm && rm.success? + get_all_properties! + self + else + raise EwsCreateItemError, "Could not update calendar item. #{rm.code}: #{rm.message_text}" if rm - data = {} - data[:conflict_resolution] = options[:conflict_resolution] || 'AutoResolve' - data[:send_meeting_invitations_or_cancellations] = - options[:send_meeting_invitations_or_cancellations] || 'SendToNone' - data[:item_changes] = [{ item_id: item_id, updates: item_updates }] - rm = ews.update_item(data).response_messages.first - if rm && rm.success? - get_all_properties! - self - else - raise EwsCreateItemError, "Could not update calendar item. #{rm.code}: #{rm.message_text}" if rm + raise EwsCreateItemError, 'Could not update calendar item.' - raise EwsCreateItemError, 'Could not update calendar item.' - - end - end + end + end - def duration_in_seconds - iso8601_duration_to_seconds(duration) - end + def duration_in_seconds + iso8601_duration_to_seconds(duration) + end - private + private - def key_paths - super.merge(CALENDAR_ITEM_KEY_PATHS) - end + def key_paths + super.merge(CALENDAR_ITEM_KEY_PATHS) + end - def key_types - super.merge(CALENDAR_ITEM_KEY_TYPES) - end + def key_types + super.merge(CALENDAR_ITEM_KEY_TYPES) + end - def key_alias - super.merge(CALENDAR_ITEM_KEY_ALIAS) + def key_alias + super.merge(CALENDAR_ITEM_KEY_ALIAS) + end + end end end end diff --git a/lib/ews/types/contact.rb b/lib/ews/types/contact.rb index e5a9c0a7..0e816c37 100644 --- a/lib/ews/types/contact.rb +++ b/lib/ews/types/contact.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class Contact - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class Contact + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/contacts_folder.rb b/lib/ews/types/contacts_folder.rb index c92aae63..b7e72b8c 100644 --- a/lib/ews/types/contacts_folder.rb +++ b/lib/ews/types/contacts_folder.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class ContactsFolder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::GenericFolder + +module Viewpoint + module EWS + module Types + class ContactsFolder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::GenericFolder + end + end end end diff --git a/lib/ews/types/copied_event.rb b/lib/ews/types/copied_event.rb index 51879583..8899f505 100644 --- a/lib/ews/types/copied_event.rb +++ b/lib/ews/types/copied_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,30 +16,34 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class CopiedEvent < Event - COPIED_EVENT_KEY_PATHS = { - old_item_id: %i[old_item_id attribs], - old_folder_id: %i[old_folder_id attribs], - old_parent_folder_id: %i[old_parent_folder_id attribs] - } +module Viewpoint + module EWS + module Types + class CopiedEvent < Event + COPIED_EVENT_KEY_PATHS = { + old_item_id: %i[old_item_id attribs], + old_folder_id: %i[old_folder_id attribs], + old_parent_folder_id: %i[old_parent_folder_id attribs] + } - COPIED_EVENT_KEY_TYPES = {} + COPIED_EVENT_KEY_TYPES = {} - COPIED_EVENT_KEY_ALIAS = {} + COPIED_EVENT_KEY_ALIAS = {} - private + private - def key_paths - @key_paths ||= super.merge COPIED_EVENT_KEY_PATHS - end + def key_paths + @key_paths ||= super.merge COPIED_EVENT_KEY_PATHS + end - def key_types - @key_types ||= super.merge COPIED_EVENT_KEY_TYPES - end + def key_types + @key_types ||= super.merge COPIED_EVENT_KEY_TYPES + end - def key_alias - @key_alias ||= super.merge COPIED_EVENT_KEY_ALIAS + def key_alias + @key_alias ||= super.merge COPIED_EVENT_KEY_ALIAS + end + end end end end diff --git a/lib/ews/types/created_event.rb b/lib/ews/types/created_event.rb index 6f98efe9..17b3d35d 100644 --- a/lib/ews/types/created_event.rb +++ b/lib/ews/types/created_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,7 +16,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class CreatedEvent < Event +module Viewpoint + module EWS + module Types + class CreatedEvent < Event + end + end end end diff --git a/lib/ews/types/deleted_event.rb b/lib/ews/types/deleted_event.rb index cf4d8abe..34a2bb97 100644 --- a/lib/ews/types/deleted_event.rb +++ b/lib/ews/types/deleted_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,7 +16,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class DeletedEvent < Event +module Viewpoint + module EWS + module Types + class DeletedEvent < Event + end + end end end diff --git a/lib/ews/types/distribution_list.rb b/lib/ews/types/distribution_list.rb index 35bca9bc..d4cc010f 100644 --- a/lib/ews/types/distribution_list.rb +++ b/lib/ews/types/distribution_list.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class DistributionList - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class DistributionList + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/event.rb b/lib/ews/types/event.rb index ba171413..c790ba60 100644 --- a/lib/ews/types/event.rb +++ b/lib/ews/types/event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,43 +16,47 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class Event - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item - - EVENT_KEY_PATHS = { - watermark: %i[watermark text], - timestamp: %i[time_stamp text], - item_id: %i[item_id attribs], - folder_id: %i[folder_id attribs], - parent_folder_id: %i[parent_folder_id attribs] - } - - EVENT_KEY_TYPES = { - timestamp: ->(ts) { DateTime.iso8601(ts) } - } - - EVENT_KEY_ALIAS = {} - - def initialize(ews, event) - @ews = ews - super(ews, event) - end - - private - - def key_paths - @key_paths ||= EVENT_KEY_PATHS - end - - def key_types - @key_types ||= EVENT_KEY_TYPES - end - - def key_alias - @key_alias ||= EVENT_KEY_ALIAS +module Viewpoint + module EWS + module Types + class Event + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + + EVENT_KEY_PATHS = { + watermark: %i[watermark text], + timestamp: %i[time_stamp text], + item_id: %i[item_id attribs], + folder_id: %i[folder_id attribs], + parent_folder_id: %i[parent_folder_id attribs] + } + + EVENT_KEY_TYPES = { + timestamp: ->(ts) { DateTime.iso8601(ts) } + } + + EVENT_KEY_ALIAS = {} + + def initialize(ews, event) + @ews = ews + super(ews, event) + end + + private + + def key_paths + @key_paths ||= EVENT_KEY_PATHS + end + + def key_types + @key_types ||= EVENT_KEY_TYPES + end + + def key_alias + @key_alias ||= EVENT_KEY_ALIAS + end + end end end end diff --git a/lib/ews/types/export_items_response_message.rb b/lib/ews/types/export_items_response_message.rb index 9b77be76..ccf42dbd 100644 --- a/lib/ews/types/export_items_response_message.rb +++ b/lib/ews/types/export_items_response_message.rb @@ -1,50 +1,55 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class ExportItemsResponseMessage - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item - - BULK_KEY_PATHS = { - id: %i[item_id attribs id], - change_key: %i[item_id attribs change_key], - data: %i[data text] - } - - BULK_KEY_TYPES = {} - - BULK_KEY_ALIAS = {} - - def initialize(ews, bulk_item) - super(ews, bulk_item) - @item = bulk_item - @ews = ews - end - def id - @item[:item_id][:attribs][:id] - end +module Viewpoint + module EWS + module Types + class ExportItemsResponseMessage + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item - def change_key - @item[:item_id][:attribs][:change_key] - end + BULK_KEY_PATHS = { + id: %i[item_id attribs id], + change_key: %i[item_id attribs change_key], + data: %i[data text] + } - def data - @item[:data][:text] - end + BULK_KEY_TYPES = {} - private + BULK_KEY_ALIAS = {} - def key_paths - @key_paths ||= BULK_KEY_PATHS - end + def initialize(ews, bulk_item) + super(ews, bulk_item) + @item = bulk_item + @ews = ews + end - def key_types - @key_types ||= BULK_KEY_TYPES - end + def id + @item[:item_id][:attribs][:id] + end + + def change_key + @item[:item_id][:attribs][:change_key] + end + + def data + @item[:data][:text] + end + + private + + def key_paths + @key_paths ||= BULK_KEY_PATHS + end + + def key_types + @key_types ||= BULK_KEY_TYPES + end - def key_alias - @key_alias ||= BULK_KEY_ALIAS + def key_alias + @key_alias ||= BULK_KEY_ALIAS + end + end end end end diff --git a/lib/ews/types/file_attachment.rb b/lib/ews/types/file_attachment.rb index b9f9d685..15509632 100644 --- a/lib/ews/types/file_attachment.rb +++ b/lib/ews/types/file_attachment.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,44 +16,49 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class FileAttachment < Attachment - FILE_ATTACH_KEY_PATHS = { - is_contact_photo?: %i[is_contact_photo text], - content: %i[content text] - } +module Viewpoint + module EWS + module Types + class FileAttachment < Attachment + FILE_ATTACH_KEY_PATHS = { + is_contact_photo?: %i[is_contact_photo text], + content: %i[content text] + } - FILE_ATTACH_KEY_TYPES = { - is_contact_photo?: ->(str) { str.downcase == 'true' } - } + FILE_ATTACH_KEY_TYPES = { + is_contact_photo?: ->(str) { str.downcase == 'true' } + } - FILE_ATTACH_KEY_ALIAS = { - file_name: :name - } + FILE_ATTACH_KEY_ALIAS = { + file_name: :name + } - def get_all_properties! - resp = ews.get_attachment attachment_ids: [id] - @ews_item.merge!(parse_response(resp)) - end + def get_all_properties! + resp = ews.get_attachment attachment_ids: [id] + @ews_item.merge!(parse_response(resp)) + end - private + private - def key_paths - super.merge(FILE_ATTACH_KEY_PATHS) - end + def key_paths + super.merge(FILE_ATTACH_KEY_PATHS) + end - def key_types - super.merge(FILE_ATTACH_KEY_TYPES) - end + def key_types + super.merge(FILE_ATTACH_KEY_TYPES) + end - def key_alias - super.merge(FILE_ATTACH_KEY_ALIAS) - end + def key_alias + super.merge(FILE_ATTACH_KEY_ALIAS) + end - def parse_response(resp) - raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + def parse_response(resp) + raise EwsError, + "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' - resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge) + resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge) + end + end end end end diff --git a/lib/ews/types/folder.rb b/lib/ews/types/folder.rb index 69904ceb..a7d2c293 100644 --- a/lib/ews/types/folder.rb +++ b/lib/ews/types/folder.rb @@ -1,55 +1,60 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class Folder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::GenericFolder - - FOLDER_KEY_PATHS = { - unread_count: %i[unread_count text] - } - FOLDER_KEY_TYPES = { - unread_count: ->(str) { str.to_i } - } - FOLDER_KEY_ALIAS = {} - - alias messages items - - def unread_messages - items read_unread_restriction - end - - def read_messages - items read_unread_restriction(true) - end - - def messages_with_attachments - opts = { restriction: { is_equal_to: [ - { field_uRI: { field_uRI: 'item:HasAttachments' } }, - { field_uRI_or_constant: { constant: { value: true } } } - ] } } - items opts - end - - private - - def read_unread_restriction(read = false) - { restriction: { is_equal_to: [ - { field_uRI: { field_uRI: 'message:IsRead' } }, - { field_uRI_or_constant: { constant: { value: read } } } - ] } } - end - - def key_paths - @key_paths ||= super.merge(FOLDER_KEY_PATHS) - end - - def key_types - @key_types ||= super.merge(FOLDER_KEY_TYPES) - end - def key_alias - @key_alias ||= super.merge(FOLDER_KEY_ALIAS) +module Viewpoint + module EWS + module Types + class Folder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::GenericFolder + + FOLDER_KEY_PATHS = { + unread_count: %i[unread_count text] + } + FOLDER_KEY_TYPES = { + unread_count: ->(str) { str.to_i } + } + FOLDER_KEY_ALIAS = {} + + alias messages items + + def unread_messages + items read_unread_restriction + end + + def read_messages + items read_unread_restriction(true) + end + + def messages_with_attachments + opts = { restriction: { is_equal_to: [ + { field_uRI: { field_uRI: 'item:HasAttachments' } }, + { field_uRI_or_constant: { constant: { value: true } } } + ] } } + items opts + end + + private + + def read_unread_restriction(read = false) + { restriction: { is_equal_to: [ + { field_uRI: { field_uRI: 'message:IsRead' } }, + { field_uRI_or_constant: { constant: { value: read } } } + ] } } + end + + def key_paths + @key_paths ||= super.merge(FOLDER_KEY_PATHS) + end + + def key_types + @key_types ||= super.merge(FOLDER_KEY_TYPES) + end + + def key_alias + @key_alias ||= super.merge(FOLDER_KEY_ALIAS) + end + end end end end diff --git a/lib/ews/types/free_busy_changed_event.rb b/lib/ews/types/free_busy_changed_event.rb index eb929207..2e9df725 100644 --- a/lib/ews/types/free_busy_changed_event.rb +++ b/lib/ews/types/free_busy_changed_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,7 +16,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class FreeBusyChangedEvent < Event +module Viewpoint + module EWS + module Types + class FreeBusyChangedEvent < Event + end + end end end diff --git a/lib/ews/types/generic_folder.rb b/lib/ews/types/generic_folder.rb index 69b0bf02..cef18711 100644 --- a/lib/ews/types/generic_folder.rb +++ b/lib/ews/types/generic_folder.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -17,365 +18,369 @@ require 'ews/item_accessors' -module Viewpoint::EWS::Types - module GenericFolder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::ItemAccessors - include Viewpoint::StringUtils - - GFOLDER_KEY_PATHS = { - folder_id: %i[folder_id attribs], - id: %i[folder_id attribs id], - change_key: %i[folder_id attribs change_key], - parent_folder_id: %i[parent_folder_id attribs id], - parent_folder_change_key: %i[parent_folder_id attribs change_key], - folder_class: %i[folder_class text], - total_count: %i[total_count text], - child_folder_count: %i[child_folder_count text], - display_name: %i[display_name text] - } - - GFOLDER_KEY_TYPES = { - total_count: ->(str) { str.to_i }, - child_folder_count: ->(str) { str.to_i } - } - - GFOLDER_KEY_ALIAS = { - name: :display_name, - ckey: :change_key - } - - attr_accessor :subscription_id, :watermark, :sync_state - - # @param [SOAP::ExchangeWebService] ews the EWS reference - # @param [Hash] ews_item the EWS parsed response document - def initialize(ews, ews_item) - super - simplify! - @sync_state = nil - @synced = false - end - - def delete! - opts = { - folder_ids: [{ id: id }], - delete_type: 'HardDelete' - } - resp = @ews.delete_folder(opts) - resp.success? || raise(EwsError, "Could not delete folder. #{resp.code}: #{resp.message}") - end +module Viewpoint + module EWS + module Types + module GenericFolder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::ItemAccessors + include Viewpoint::StringUtils + + GFOLDER_KEY_PATHS = { + folder_id: %i[folder_id attribs], + id: %i[folder_id attribs id], + change_key: %i[folder_id attribs change_key], + parent_folder_id: %i[parent_folder_id attribs id], + parent_folder_change_key: %i[parent_folder_id attribs change_key], + folder_class: %i[folder_class text], + total_count: %i[total_count text], + child_folder_count: %i[child_folder_count text], + display_name: %i[display_name text] + } - def items(opts = {}) - args = items_args(opts.clone) - obj = OpenStruct.new(opts: args, restriction: {}) - yield obj if block_given? - merge_restrictions! obj - resp = ews.find_item(args) - items_parser resp - end + GFOLDER_KEY_TYPES = { + total_count: ->(str) { str.to_i }, + child_folder_count: ->(str) { str.to_i } + } - # Fetch items since a give DateTime - # @param [DateTime] date_time the time to fetch Items since. - def items_since(date_time, opts = {}) - opts = opts.clone - raise EwsBadArgumentError, 'First argument must be a Date or DateTime' unless date_time.is_a?(Date) + GFOLDER_KEY_ALIAS = { + name: :display_name, + ckey: :change_key + } - restr = { restriction: { is_greater_than_or_equal_to: [{ field_uRI: { field_uRI: 'item:DateTimeReceived' } }, - { field_uRI_or_constant: { constant: { value: date_time.to_datetime } } }] } } - items(opts.merge(restr)) - end + attr_accessor :subscription_id, :watermark, :sync_state - # Fetch only items from today (since midnight) - def todays_items(_opts = {}) - items_since(Date.today) - end + # @param [SOAP::ExchangeWebService] ews the EWS reference + # @param [Hash] ews_item the EWS parsed response document + def initialize(ews, ews_item) + super + simplify! + @sync_state = nil + @synced = false + end - # Fetch items between a given time period - # @param [DateTime] start_date the time to start fetching Items from - # @param [DateTime] end_date the time to stop fetching Items from - def items_between(start_date, end_date, _opts = {}) - items do |obj| - obj.restriction = { and: [ - { is_greater_than_or_equal_to: [ - { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, - { field_uRI_or_constant: { constant: { value: start_date } } } - ] }, - { is_less_than_or_equal_to: [ - { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, - { field_uRI_or_constant: { constant: { value: end_date } } } - ] } - ] } - end - end + def delete! + opts = { + folder_ids: [{ id: id }], + delete_type: 'HardDelete' + } + resp = @ews.delete_folder(opts) + resp.success? || raise(EwsError, "Could not delete folder. #{resp.code}: #{resp.message}") + end - # Search on the item subject - # @param [String] match_str A simple string paramater to match against the - # subject. The search ignores case and does not accept regexes... only strings. - # @param [String,nil] exclude_str A string to exclude from matches against - # the subject. This is optional. - def search_by_subject(match_str, exclude_str = nil) - items do |obj| - match = { contains: { - containment_mode: 'Substring', - containment_comparison: 'IgnoreCase', - field_uRI: { field_uRI: 'item:Subject' }, - constant: { value: match_str } - } } - unless exclude_str.nil? - excl = { not: { contains: { - containment_mode: 'Substring', - containment_comparison: 'IgnoreCase', - field_uRI: { field_uRI: 'item:Subject' }, - constant: { value: exclude_str } - } } } - - match[:and] = [{ contains: match.delete(:contains) }, excl] + def items(opts = {}) + args = items_args(opts.clone) + obj = OpenStruct.new(opts: args, restriction: {}) + yield obj if block_given? + merge_restrictions! obj + resp = ews.find_item(args) + items_parser resp end - obj.restriction = match - end - end - def get_all_properties! - @ews_item = get_folder(base_shape: 'AllProperties') - simplify! - end + # Fetch items since a give DateTime + # @param [DateTime] date_time the time to fetch Items since. + def items_since(date_time, opts = {}) + opts = opts.clone + raise EwsBadArgumentError, 'First argument must be a Date or DateTime' unless date_time.is_a?(Date) - def available_categories - opts = { - user_config_name: { - name: 'CategoryList', - distinguished_folder_id: { id: :calendar } - }, - user_config_props: 'XmlData' - } - ews.get_user_configuration(opts) - # txt = resp.response_message[:elems][:get_user_configuration_response_message][:elems][1][:user_configuration][:elems][1][:xml_data][:text] - # Base64.decode64 txt - end + restr = { restriction: { is_greater_than_or_equal_to: [{ field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: date_time.to_datetime } } }] } } + items(opts.merge(restr)) + end - # Syncronize Items in this folder. If this method is issued multiple - # times it will continue where the last sync completed. - # @param [Integer] sync_amount The number of items to synchronize per sync - # @param [Boolean] sync_all Whether to sync all the data by looping through. - # The default is to just sync the first set. You can manually loop through - # with multiple calls to #sync_items! - # @return [Hash] Returns a hash with keys for each change type that ocurred. - # Possible key values are: - # (:create/:udpate/:delete/:read_flag_change). - # For :deleted and :read_flag_change items a simple hash with :id and - # :change_key is returned. - # See: http://msdn.microsoft.com/en-us/library/aa565609.aspx - def sync_items!(sync_state = nil, sync_amount = 256, _sync_all = false, opts = {}) - item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : { base_shape: :default } - sync_state ||= @sync_state - - resp = ews.sync_folder_items item_shape: item_shape, - sync_folder_id: folder_id, max_changes_returned: sync_amount, sync_state: sync_state - rmsg = resp.response_messages[0] - - raise EwsError, "Could not synchronize: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? - - @synced = rmsg.includes_last_item_in_range? - @sync_state = rmsg.sync_state - rhash = {} - rmsg.changes.each do |c| - ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) - if %i[delete read_flag_change].include?(ctype) - rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs] - else - type = c[ctype][:elems][0].keys.first - item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) - rhash[ctype] << item + # Fetch only items from today (since midnight) + def todays_items(_opts = {}) + items_since(Date.today) end - end - rhash - end - def synced? - @synced - end + # Fetch items between a given time period + # @param [DateTime] start_date the time to start fetching Items from + # @param [DateTime] end_date the time to stop fetching Items from + def items_between(start_date, end_date, _opts = {}) + items do |obj| + obj.restriction = { and: [ + { is_greater_than_or_equal_to: [ + { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: start_date } } } + ] }, + { is_less_than_or_equal_to: [ + { field_uRI: { field_uRI: 'item:DateTimeReceived' } }, + { field_uRI_or_constant: { constant: { value: end_date } } } + ] } + ] } + end + end - # Subscribe this folder to events. This method initiates an Exchange pull - # type subscription. - # - # @param event_types [Array] Which event types to subscribe to. By default - # we subscribe to all Exchange event types: :all, :copied, :created, - # :deleted, :modified, :moved, :new_mail, :free_busy_changed - # @param watermark [String] pass a watermark if you wish to start the - # subscription at a specific point. - # @param timeout [Fixnum] the time in minutes that the subscription can - # remain idle between calls to #get_events. default: 240 minutes - # @return [Boolean] Did the subscription happen successfully? - def subscribe(evtypes = [:all], watermark = nil, timeout = 240) - # Refresh the subscription if already subscribed - unsubscribe if subscribed? - - event_types = normalize_event_names(evtypes) - folder = { id: id, change_key: change_key } - resp = ews.pull_subscribe_folder(folder, event_types, timeout, watermark) - rmsg = resp.response_messages.first - raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? - - @subscription_id = rmsg.subscription_id - @watermark = rmsg.watermark - true - end + # Search on the item subject + # @param [String] match_str A simple string paramater to match against the + # subject. The search ignores case and does not accept regexes... only strings. + # @param [String,nil] exclude_str A string to exclude from matches against + # the subject. This is optional. + def search_by_subject(match_str, exclude_str = nil) + items do |obj| + match = { contains: { + containment_mode: 'Substring', + containment_comparison: 'IgnoreCase', + field_uRI: { field_uRI: 'item:Subject' }, + constant: { value: match_str } + } } + unless exclude_str.nil? + excl = { not: { contains: { + containment_mode: 'Substring', + containment_comparison: 'IgnoreCase', + field_uRI: { field_uRI: 'item:Subject' }, + constant: { value: exclude_str } + } } } + + match[:and] = [{ contains: match.delete(:contains) }, excl] + end + obj.restriction = match + end + end - def push_subscribe(url, evtypes = [:all], watermark = nil, status_frequency = nil) - event_types = normalize_event_names(evtypes) - folder = { id: id, change_key: change_key } - resp = ews.push_subscribe_folder(folder, event_types, url, status_frequency, watermark) - rmsg = resp.response_messages.first - raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + def get_all_properties! + @ews_item = get_folder(base_shape: 'AllProperties') + simplify! + end - @subscription_id = rmsg.subscription_id - @watermark = rmsg.watermark - true - end + def available_categories + opts = { + user_config_name: { + name: 'CategoryList', + distinguished_folder_id: { id: :calendar } + }, + user_config_props: 'XmlData' + } + ews.get_user_configuration(opts) + # txt = resp.response_message[:elems][:get_user_configuration_response_message][:elems][1][:user_configuration][:elems][1][:xml_data][:text] + # Base64.decode64 txt + end - # Check if there is a subscription for this folder. - # @return [Boolean] Are we subscribed to this folder? - def subscribed? - (@subscription_id.nil? or @watermark.nil?) ? false : true - end + # Syncronize Items in this folder. If this method is issued multiple + # times it will continue where the last sync completed. + # @param [Integer] sync_amount The number of items to synchronize per sync + # @param [Boolean] sync_all Whether to sync all the data by looping through. + # The default is to just sync the first set. You can manually loop through + # with multiple calls to #sync_items! + # @return [Hash] Returns a hash with keys for each change type that ocurred. + # Possible key values are: + # (:create/:udpate/:delete/:read_flag_change). + # For :deleted and :read_flag_change items a simple hash with :id and + # :change_key is returned. + # See: http://msdn.microsoft.com/en-us/library/aa565609.aspx + def sync_items!(sync_state = nil, sync_amount = 256, _sync_all = false, opts = {}) + item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : { base_shape: :default } + sync_state ||= @sync_state + + resp = ews.sync_folder_items item_shape: item_shape, + sync_folder_id: folder_id, max_changes_returned: sync_amount, sync_state: sync_state + rmsg = resp.response_messages[0] + + raise EwsError, "Could not synchronize: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @synced = rmsg.includes_last_item_in_range? + @sync_state = rmsg.sync_state + rhash = {} + rmsg.changes.each do |c| + ctype = c.keys.first + rhash[ctype] = [] unless rhash.has_key?(ctype) + if %i[delete read_flag_change].include?(ctype) + rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs] + else + type = c[ctype][:elems][0].keys.first + item = class_by_name(type).new(ews, c[ctype][:elems][0][type]) + rhash[ctype] << item + end + end + rhash + end - # Unsubscribe this folder from further Exchange events. - # @return [Boolean] Did we unsubscribe successfully? - def unsubscribe - return true if @subscription_id.nil? + def synced? + @synced + end - resp = ews.unsubscribe(@subscription_id) - rmsg = resp.response_messages.first - raise EwsSubscriptionError, "Could not unsubscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + # Subscribe this folder to events. This method initiates an Exchange pull + # type subscription. + # + # @param event_types [Array] Which event types to subscribe to. By default + # we subscribe to all Exchange event types: :all, :copied, :created, + # :deleted, :modified, :moved, :new_mail, :free_busy_changed + # @param watermark [String] pass a watermark if you wish to start the + # subscription at a specific point. + # @param timeout [Fixnum] the time in minutes that the subscription can + # remain idle between calls to #get_events. default: 240 minutes + # @return [Boolean] Did the subscription happen successfully? + def subscribe(evtypes = [:all], watermark = nil, timeout = 240) + # Refresh the subscription if already subscribed + unsubscribe if subscribed? + + event_types = normalize_event_names(evtypes) + folder = { id: id, change_key: change_key } + resp = ews.pull_subscribe_folder(folder, event_types, timeout, watermark) + rmsg = resp.response_messages.first + raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? + + @subscription_id = rmsg.subscription_id + @watermark = rmsg.watermark + true + end - @subscription_id = nil - @watermark = nil - true - end + def push_subscribe(url, evtypes = [:all], watermark = nil, status_frequency = nil) + event_types = normalize_event_names(evtypes) + folder = { id: id, change_key: change_key } + resp = ews.push_subscribe_folder(folder, event_types, url, status_frequency, watermark) + rmsg = resp.response_messages.first + raise EwsSubscriptionError, "Could not subscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? - # Checks a subscribed folder for events - # @return [Array] An array of Event items - def get_events - if subscribed? - resp = ews.get_events(@subscription_id, @watermark) - rmsg = resp.response_messages[0] - @watermark = rmsg.new_watermark - # @todo if parms[:more_events] # get more events - rmsg.events.collect { |ev| - type = ev.keys.first - class_by_name(type).new(ews, ev[type]) - } - else - raise EwsSubscriptionError, - "Folder <#{display_name}> not subscribed to. Issue a Folder#subscribe before checking events." - end - rescue EwsSubscriptionTimeout => e - @subscription_id = nil - @watermark = nil - raise e - end + @subscription_id = rmsg.subscription_id + @watermark = rmsg.watermark + true + end - private + # Check if there is a subscription for this folder. + # @return [Boolean] Are we subscribed to this folder? + def subscribed? + (@subscription_id.nil? or @watermark.nil?) ? false : true + end - def key_paths - @key_paths ||= super.merge(GFOLDER_KEY_PATHS) - end + # Unsubscribe this folder from further Exchange events. + # @return [Boolean] Did we unsubscribe successfully? + def unsubscribe + return true if @subscription_id.nil? - def key_types - @key_types ||= super.merge(GFOLDER_KEY_TYPES) - end + resp = ews.unsubscribe(@subscription_id) + rmsg = resp.response_messages.first + raise EwsSubscriptionError, "Could not unsubscribe: #{rmsg.code}: #{rmsg.message_text}" unless rmsg.success? - def key_alias - @key_alias ||= super.merge(GFOLDER_KEY_ALIAS) - end + @subscription_id = nil + @watermark = nil + true + end - def simplify! - @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| - key = i.keys.first - if o.has_key?(key) - if o[key].is_a?(Array) - o[key] << i[key] + # Checks a subscribed folder for events + # @return [Array] An array of Event items + def get_events + if subscribed? + resp = ews.get_events(@subscription_id, @watermark) + rmsg = resp.response_messages[0] + @watermark = rmsg.new_watermark + # @todo if parms[:more_events] # get more events + rmsg.events.collect { |ev| + type = ev.keys.first + class_by_name(type).new(ews, ev[type]) + } else - o[key] = [o.delete(key), i[key]] + raise EwsSubscriptionError, + "Folder <#{display_name}> not subscribed to. Issue a Folder#subscribe before checking events." end - else - o[key] = i[key] + rescue EwsSubscriptionTimeout => e + @subscription_id = nil + @watermark = nil + raise e end - end - end - # Get a specific folder by its ID. - # @param [Hash] opts Misc options to control request - # @option opts [String] :base_shape IdOnly/Default/AllProperties - # @raise [EwsError] raised when the backend SOAP method returns an error. - def get_folder(opts = {}) - args = get_folder_args(opts) - resp = ews.get_folder(args) - get_folder_parser(resp) - end + private - # Build up the arguements for #get_folder - # @todo: should we really pass the ChangeKey or do we want the freshest obj? - def get_folder_args(opts) - opts[:base_shape] ||= 'Default' - default_args = { - folder_ids: [{ id: id, change_key: change_key }], - folder_shape: { base_shape: opts[:base_shape] } - } - default_args.merge(opts) - end + def key_paths + @key_paths ||= super.merge(GFOLDER_KEY_PATHS) + end - def get_folder_parser(resp) - raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + def key_types + @key_types ||= super.merge(GFOLDER_KEY_TYPES) + end - f = resp.response_message[:elems][:folders][:elems][0] - f.values.first - end + def key_alias + @key_alias ||= super.merge(GFOLDER_KEY_ALIAS) + end - def items_args(opts) - { - parent_folder_ids: [{ id: id }], - traversal: 'Shallow', - item_shape: { base_shape: 'Default' } - }.merge(opts) - end + def simplify! + @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| + key = i.keys.first + if o.has_key?(key) + if o[key].is_a?(Array) + o[key] << i[key] + else + o[key] = [o.delete(key), i[key]] + end + else + o[key] = i[key] + end + end + end - def items_parser(resp) - rm = resp.response_messages[0] - raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + # Get a specific folder by its ID. + # @param [Hash] opts Misc options to control request + # @option opts [String] :base_shape IdOnly/Default/AllProperties + # @raise [EwsError] raised when the backend SOAP method returns an error. + def get_folder(opts = {}) + args = get_folder_args(opts) + resp = ews.get_folder(args) + get_folder_parser(resp) + end - items = [] - rm.root_folder.items.each do |i| - type = i.keys.first - items << class_by_name(type).new(ews, i[type], self) - end - items - end + # Build up the arguements for #get_folder + # @todo: should we really pass the ChangeKey or do we want the freshest obj? + def get_folder_args(opts) + opts[:base_shape] ||= 'Default' + default_args = { + folder_ids: [{ id: id, change_key: change_key }], + folder_shape: { base_shape: opts[:base_shape] } + } + default_args.merge(opts) + end - def merge_restrictions!(obj, merge_type = :and) - if obj.opts[:restriction] && !obj.opts[:restriction].empty? && !obj.restriction.empty? - obj.opts[:restriction] = { - merge_type => [ - obj.opts.delete(:restriction), - obj.restriction - ] - } - elsif !obj.restriction.empty? - obj.opts[:restriction] = obj.restriction - end - end + def get_folder_parser(resp) + raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + + f = resp.response_message[:elems][:folders][:elems][0] + f.values.first + end + + def items_args(opts) + { + parent_folder_ids: [{ id: id }], + traversal: 'Shallow', + item_shape: { base_shape: 'Default' } + }.merge(opts) + end - def normalize_event_names(events) - events = %i[copied created deleted modified moved new_mail free_busy_changed] if events.include?(:all) + def items_parser(resp) + rm = resp.response_messages[0] + raise EwsError, "Could not retrieve folder. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' - events.collect do |ev| - nev = ruby_case(ev) - if nev.end_with?('_event') - nev.to_sym - else - "#{nev}_event".to_sym + items = [] + rm.root_folder.items.each do |i| + type = i.keys.first + items << class_by_name(type).new(ews, i[type], self) + end + items + end + + def merge_restrictions!(obj, merge_type = :and) + if obj.opts[:restriction] && !obj.opts[:restriction].empty? && !obj.restriction.empty? + obj.opts[:restriction] = { + merge_type => [ + obj.opts.delete(:restriction), + obj.restriction + ] + } + elsif !obj.restriction.empty? + obj.opts[:restriction] = obj.restriction + end + end + + def normalize_event_names(events) + events = %i[copied created deleted modified moved new_mail free_busy_changed] if events.include?(:all) + + events.collect do |ev| + nev = ruby_case(ev) + if nev.end_with?('_event') + nev.to_sym + else + "#{nev}_event".to_sym + end + end end end end diff --git a/lib/ews/types/item.rb b/lib/ews/types/item.rb index a5125791..7f30631b 100644 --- a/lib/ews/types/item.rb +++ b/lib/ews/types/item.rb @@ -1,439 +1,446 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - module Item - include Viewpoint::EWS - include Viewpoint::EWS::Types - include ItemFieldUriMap - - def self.included(klass) - klass.extend ClassMethods - end - module ClassMethods - def init_simple_item(ews, id, change_key = nil, parent = nil) - ews_item = { item_id: { attribs: { id: id, change_key: change_key } } } - new ews, ews_item, parent - end - end +module Viewpoint + module EWS + module Types + module Item + include Viewpoint::EWS + include Viewpoint::EWS::Types + include ItemFieldUriMap + + def self.included(klass) + klass.extend ClassMethods + end + + module ClassMethods + def init_simple_item(ews, id, change_key = nil, parent = nil) + ews_item = { item_id: { attribs: { id: id, change_key: change_key } } } + new ews, ews_item, parent + end + end - ITEM_KEY_PATHS = { - item_id: %i[item_id attribs], - id: %i[item_id attribs id], - change_key: %i[item_id attribs change_key], - subject: %i[subject text], - sensitivity: %i[sensitivity text], - size: %i[size text], - date_time_sent: %i[date_time_sent text], - date_time_created: %i[date_time_created text], - last_modified_time: %i[last_modified_time text], - mime_content: %i[mime_content text], - has_attachments?: %i[has_attachments text], - is_associated?: %i[is_associated text], - is_read?: %i[is_read text], - is_draft?: %i[is_draft text], - is_submitted?: %i[is_submitted text], - conversation_id: %i[conversation_id attribs id], - categories: %i[categories elems], - internet_message_id: %i[internet_message_id text], - internet_message_headers: %i[internet_message_headers elems], - sender: [:sender, :elems, 0, :mailbox, :elems], - from: [:from, :elems, 0, :mailbox, :elems], - to_recipients: %i[to_recipients elems], - cc_recipients: %i[cc_recipients elems], - attachments: %i[attachments elems], - importance: %i[importance text], - conversation_index: %i[conversation_index text], - conversation_topic: %i[conversation_topic text], - body_type: %i[body attribs body_type], - body: %i[body text] - } - - ITEM_KEY_TYPES = { - size: ->(str) { str.to_i }, - date_time_sent: ->(str) { DateTime.parse(str) }, - date_time_created: ->(str) { DateTime.parse(str) }, - last_modified_time: ->(str) { DateTime.parse(str) }, - has_attachments?: ->(str) { str.downcase == 'true' }, - is_associated?: ->(str) { str.downcase == 'true' }, - is_read?: ->(str) { str.downcase == 'true' }, - is_draft?: ->(str) { str.downcase == 'true' }, - is_submitted?: ->(str) { str.downcase == 'true' }, - categories: ->(obj) { obj.collect { |s| s[:string][:text] } }, - internet_message_headers: lambda { |obj| - obj.collect { |h| - { h[:internet_message_header][:attribs][:header_name] => - h[:internet_message_header][:text] } + ITEM_KEY_PATHS = { + item_id: %i[item_id attribs], + id: %i[item_id attribs id], + change_key: %i[item_id attribs change_key], + subject: %i[subject text], + sensitivity: %i[sensitivity text], + size: %i[size text], + date_time_sent: %i[date_time_sent text], + date_time_created: %i[date_time_created text], + last_modified_time: %i[last_modified_time text], + mime_content: %i[mime_content text], + has_attachments?: %i[has_attachments text], + is_associated?: %i[is_associated text], + is_read?: %i[is_read text], + is_draft?: %i[is_draft text], + is_submitted?: %i[is_submitted text], + conversation_id: %i[conversation_id attribs id], + categories: %i[categories elems], + internet_message_id: %i[internet_message_id text], + internet_message_headers: %i[internet_message_headers elems], + sender: [:sender, :elems, 0, :mailbox, :elems], + from: [:from, :elems, 0, :mailbox, :elems], + to_recipients: %i[to_recipients elems], + cc_recipients: %i[cc_recipients elems], + attachments: %i[attachments elems], + importance: %i[importance text], + conversation_index: %i[conversation_index text], + conversation_topic: %i[conversation_topic text], + body_type: %i[body attribs body_type], + body: %i[body text] } - }, - sender: :build_mailbox_user, - from: :build_mailbox_user, - to_recipients: :build_mailbox_users, - cc_recipients: :build_mailbox_users, - attachments: :build_attachments - } - - ITEM_KEY_ALIAS = { - read?: :is_read?, - draft?: :is_draft?, - submitted?: :is_submitted?, - associated?: :is_associated? - } - - attr_reader :ews_item, :parent - - # @param ews [SOAP::ExchangeWebService] the EWS reference - # @param ews_item [Hash] the EWS parsed response document - # @param parent [GenericFolder] an optional parent object - def initialize(ews, ews_item, parent = nil) - super(ews, ews_item) - @parent = parent - @body_type = false - simplify! - @new_file_attachments = [] - @new_item_attachments = [] - @new_inline_attachments = [] - end - # Specify a body_type to fetch this item with if it hasn't already been fetched. - # @param body_type [String, Symbol, FalseClass] must be :best, :text, or - # :html. You can also set it to false to make it use the default. - def default_body_type=(body_type) - @body_type = body_type - end + ITEM_KEY_TYPES = { + size: ->(str) { str.to_i }, + date_time_sent: ->(str) { DateTime.parse(str) }, + date_time_created: ->(str) { DateTime.parse(str) }, + last_modified_time: ->(str) { DateTime.parse(str) }, + has_attachments?: ->(str) { str.downcase == 'true' }, + is_associated?: ->(str) { str.downcase == 'true' }, + is_read?: ->(str) { str.downcase == 'true' }, + is_draft?: ->(str) { str.downcase == 'true' }, + is_submitted?: ->(str) { str.downcase == 'true' }, + categories: ->(obj) { obj.collect { |s| s[:string][:text] } }, + internet_message_headers: lambda { |obj| + obj.collect { |h| + { h[:internet_message_header][:attribs][:header_name] => + h[:internet_message_header][:text] } + } + }, + sender: :build_mailbox_user, + from: :build_mailbox_user, + to_recipients: :build_mailbox_users, + cc_recipients: :build_mailbox_users, + attachments: :build_attachments + } - def delete!(deltype = :hard, opts = {}) - opts = { - delete_type: delete_type(deltype), - item_ids: [{ item_id: { id: id } }] - }.merge(opts) + ITEM_KEY_ALIAS = { + read?: :is_read?, + draft?: :is_draft?, + submitted?: :is_submitted?, + associated?: :is_associated? + } - resp = @ews.delete_item(opts) - rmsg = resp.response_messages[0] - raise EwsError, "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + attr_reader :ews_item, :parent + + # @param ews [SOAP::ExchangeWebService] the EWS reference + # @param ews_item [Hash] the EWS parsed response document + # @param parent [GenericFolder] an optional parent object + def initialize(ews, ews_item, parent = nil) + super(ews, ews_item) + @parent = parent + @body_type = false + simplify! + @new_file_attachments = [] + @new_item_attachments = [] + @new_inline_attachments = [] + end - true - end + # Specify a body_type to fetch this item with if it hasn't already been fetched. + # @param body_type [String, Symbol, FalseClass] must be :best, :text, or + # :html. You can also set it to false to make it use the default. + def default_body_type=(body_type) + @body_type = body_type + end - def recycle! - delete! :recycle - end + def delete!(deltype = :hard, opts = {}) + opts = { + delete_type: delete_type(deltype), + item_ids: [{ item_id: { id: id } }] + }.merge(opts) - def get_all_properties! - @ews_item = get_item(base_shape: 'AllProperties') - simplify! - end + resp = @ews.delete_item(opts) + rmsg = resp.response_messages[0] + raise EwsError, + "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? - # Mark an item as read - def mark_read! - update_is_read_status true - end + true + end - # Mark an item as unread - def mark_unread! - update_is_read_status false - end + def recycle! + delete! :recycle + end - # Move this item to a new folder - # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should - # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) - # @return [String] the new Id of the moved item - def move!(new_folder) - new_folder = new_folder.id if new_folder.is_a?(GenericFolder) - move_opts = { - to_folder_id: { id: new_folder }, - item_ids: [{ item_id: { id: id } }] - } - resp = @ews.move_item(move_opts) - rmsg = resp.response_messages[0] - - raise EwsError, "Could not move item. #{resp.code}: #{resp.message}" unless rmsg.success? - - obj = rmsg.items.first - itype = obj.keys.first - obj[itype][:elems][0][:item_id][:attribs][:id] - end + def get_all_properties! + @ews_item = get_item(base_shape: 'AllProperties') + simplify! + end - # Copy this item to a new folder - # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should - # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) - # @return [String] the new Id of the copied item - def copy(new_folder) - new_folder = new_folder.id if new_folder.is_a?(GenericFolder) - copy_opts = { - to_folder_id: { id: new_folder }, - item_ids: [{ item_id: { id: id } }] - } - resp = @ews.copy_item(copy_opts) - rmsg = resp.response_messages[0] - - raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? - - obj = rmsg.items.first - itype = obj.keys.first - obj[itype][:elems][0][:item_id][:attribs][:id] - end + # Mark an item as read + def mark_read! + update_is_read_status true + end - def add_file_attachment(file) - fa = OpenStruct.new - fa.name = File.basename(file.path) - fa.content = Base64.encode64(file.read) - @new_file_attachments << fa - end + # Mark an item as unread + def mark_unread! + update_is_read_status false + end - def add_item_attachment(other_item, name = nil) - ia = OpenStruct.new - ia.name = (name || other_item.subject) - ia.item = { id: other_item.id, change_key: other_item.change_key } - @new_item_attachments << ia - end + # Move this item to a new folder + # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should + # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) + # @return [String] the new Id of the moved item + def move!(new_folder) + new_folder = new_folder.id if new_folder.is_a?(GenericFolder) + move_opts = { + to_folder_id: { id: new_folder }, + item_ids: [{ item_id: { id: id } }] + } + resp = @ews.move_item(move_opts) + rmsg = resp.response_messages[0] - def add_inline_attachment(file) - fi = OpenStruct.new - fi.name = File.basename(file.path) - fi.content = Base64.encode64(file.read) - @new_inline_attachments << fi - end + raise EwsError, "Could not move item. #{resp.code}: #{resp.message}" unless rmsg.success? - def submit! - if draft? - submit_attachments! - resp = ews.send_item(item_ids: [{ item_id: { id: id, change_key: change_key } }]) - rm = resp.response_messages[0] - rm.success? || raise(EwsSendItemError, "#{rm.code}: #{rm.message_text}") - else - false - end - end + obj = rmsg.items.first + itype = obj.keys.first + obj[itype][:elems][0][:item_id][:attribs][:id] + end - def submit_attachments! - unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?) - return false - end + # Copy this item to a new folder + # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should + # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String) + # @return [String] the new Id of the copied item + def copy(new_folder) + new_folder = new_folder.id if new_folder.is_a?(GenericFolder) + copy_opts = { + to_folder_id: { id: new_folder }, + item_ids: [{ item_id: { id: id } }] + } + resp = @ews.copy_item(copy_opts) + rmsg = resp.response_messages[0] - opts = { - parent_id: { id: id, change_key: change_key }, - files: @new_file_attachments, - items: @new_item_attachments, - inline_files: @new_inline_attachments - } - resp = ews.create_attachment(opts) - set_change_key resp.response_messages[0].attachments[0].parent_change_key - @new_file_attachments = [] - @new_item_attachments = [] - @new_inline_attachments = [] - end + raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? - # If you want to add to the body set #new_body_content. If you set #body - # it will override the body that is there. - # @see MessageAccessors#send_message for options - # additional options: - # :new_body_content, :new_body_type - # @example - # item.forward do |i| - # i.new_body_content = "Add this to the top" - # i.to_recipients << 'test@example.com' - # end - def forward(opts = {}) - msg = Template::ForwardItem.new opts.clone - yield msg if block_given? - msg.reference_item_id = { id: id, change_key: change_key } - dispatch_create_item! msg - end + obj = rmsg.items.first + itype = obj.keys.first + obj[itype][:elems][0][:item_id][:attribs][:id] + end - def reply_to(opts = {}) - msg = Template::ReplyToItem.new opts.clone - yield msg if block_given? - msg.reference_item_id = { id: id, change_key: change_key } - dispatch_create_item! msg - end + def add_file_attachment(file) + fa = OpenStruct.new + fa.name = File.basename(file.path) + fa.content = Base64.encode64(file.read) + @new_file_attachments << fa + end - def reply_to_all(opts = {}) - msg = Template::ReplyToItem.new opts.clone - yield msg if block_given? - msg.reference_item_id = { id: id, change_key: change_key } - msg.ews_type = :reply_all_to_item - dispatch_create_item! msg - end + def add_item_attachment(other_item, name = nil) + ia = OpenStruct.new + ia.name = (name || other_item.subject) + ia.item = { id: other_item.id, change_key: other_item.change_key } + @new_item_attachments << ia + end - private + def add_inline_attachment(file) + fi = OpenStruct.new + fi.name = File.basename(file.path) + fi.content = Base64.encode64(file.read) + @new_inline_attachments << fi + end - def key_paths - super.merge(ITEM_KEY_PATHS) - end + def submit! + if draft? + submit_attachments! + resp = ews.send_item(item_ids: [{ item_id: { id: id, change_key: change_key } }]) + rm = resp.response_messages[0] + rm.success? || raise(EwsSendItemError, "#{rm.code}: #{rm.message_text}") + else + false + end + end - def key_types - super.merge(ITEM_KEY_TYPES) - end + def submit_attachments! + unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?) + return false + end - def key_alias - super.merge(ITEM_KEY_ALIAS) - end + opts = { + parent_id: { id: id, change_key: change_key }, + files: @new_file_attachments, + items: @new_item_attachments, + inline_files: @new_inline_attachments + } + resp = ews.create_attachment(opts) + set_change_key resp.response_messages[0].attachments[0].parent_change_key + @new_file_attachments = [] + @new_item_attachments = [] + @new_inline_attachments = [] + end - def update_is_read_status(read) - field = :is_read - opts = { item_changes: - [ - { item_id: { id: id, change_key: change_key }, - updates: [ - { set_item_field: { field_uRI: { field_uRI: FIELD_URIS[field][:text] }, - message: { sub_elements: [{ field => { text: read } }] } } } - ] } - ] } - resp = ews.update_item({ conflict_resolution: 'AutoResolve' }.merge(opts)) - rmsg = resp.response_messages[0] - raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + # If you want to add to the body set #new_body_content. If you set #body + # it will override the body that is there. + # @see MessageAccessors#send_message for options + # additional options: + # :new_body_content, :new_body_type + # @example + # item.forward do |i| + # i.new_body_content = "Add this to the top" + # i.to_recipients << 'test@example.com' + # end + def forward(opts = {}) + msg = Template::ForwardItem.new opts.clone + yield msg if block_given? + msg.reference_item_id = { id: id, change_key: change_key } + dispatch_create_item! msg + end - true - end + def reply_to(opts = {}) + msg = Template::ReplyToItem.new opts.clone + yield msg if block_given? + msg.reference_item_id = { id: id, change_key: change_key } + dispatch_create_item! msg + end - def simplify! - return unless @ews_item.has_key?(:elems) + def reply_to_all(opts = {}) + msg = Template::ReplyToItem.new opts.clone + yield msg if block_given? + msg.reference_item_id = { id: id, change_key: change_key } + msg.ews_type = :reply_all_to_item + dispatch_create_item! msg + end - @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| - key = i.keys.first - if o.has_key?(key) - if o[key].is_a?(Array) - o[key] << i[key] - else - o[key] = [o.delete(key), i[key]] + private + + def key_paths + super.merge(ITEM_KEY_PATHS) + end + + def key_types + super.merge(ITEM_KEY_TYPES) + end + + def key_alias + super.merge(ITEM_KEY_ALIAS) + end + + def update_is_read_status(read) + field = :is_read + opts = { item_changes: + [ + { item_id: { id: id, change_key: change_key }, + updates: [ + { set_item_field: { field_uRI: { field_uRI: FIELD_URIS[field][:text] }, + message: { sub_elements: [{ field => { text: read } }] } } } + ] } + ] } + resp = ews.update_item({ conflict_resolution: 'AutoResolve' }.merge(opts)) + rmsg = resp.response_messages[0] + raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + + true + end + + def simplify! + return unless @ews_item.has_key?(:elems) + + @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| + key = i.keys.first + if o.has_key?(key) + if o[key].is_a?(Array) + o[key] << i[key] + else + o[key] = [o.delete(key), i[key]] + end + else + o[key] = i[key] + end end - else - o[key] = i[key] end - end - end - # Get a specific item by its ID. - # @param [Hash] opts Misc options to control request - # @option opts [String] :base_shape IdOnly/Default/AllProperties - # @raise [EwsError] raised when the backend SOAP method returns an error. - def get_item(opts = {}) - args = get_item_args(opts) - resp = ews.get_item(args) - get_item_parser(resp) - end + # Get a specific item by its ID. + # @param [Hash] opts Misc options to control request + # @option opts [String] :base_shape IdOnly/Default/AllProperties + # @raise [EwsError] raised when the backend SOAP method returns an error. + def get_item(opts = {}) + args = get_item_args(opts) + resp = ews.get_item(args) + get_item_parser(resp) + end - # Build up the arguements for #get_item - # @todo: should we really pass the ChangeKey or do we want the freshest obj? - def get_item_args(opts) - opts[:base_shape] ||= 'Default' - default_args = { - item_shape: { base_shape: opts[:base_shape] }, - item_ids: [{ item_id: { id: id, change_key: change_key } }] - } - default_args[:item_shape][:body_type] = @body_type if @body_type - default_args - end + # Build up the arguements for #get_item + # @todo: should we really pass the ChangeKey or do we want the freshest obj? + def get_item_args(opts) + opts[:base_shape] ||= 'Default' + default_args = { + item_shape: { base_shape: opts[:base_shape] }, + item_ids: [{ item_id: { id: id, change_key: change_key } }] + } + default_args[:item_shape][:body_type] = @body_type if @body_type + default_args + end - def get_item_parser(resp) - rm = resp.response_messages[0] - raise EwsError, "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + def get_item_parser(resp) + rm = resp.response_messages[0] + raise EwsError, + "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' - rm.items[0].values.first - end + rm.items[0].values.first + end - # Map a delete type to what EWS expects - # @param [Symbol] type. Must be :hard, :soft, or :recycle - def delete_type(type) - case type - when :hard then 'HardDelete' - when :soft then 'SoftDelete' - when :recycle then 'MoveToDeletedItems' - else 'MoveToDeletedItems' - end - end + # Map a delete type to what EWS expects + # @param [Symbol] type. Must be :hard, :soft, or :recycle + def delete_type(type) + case type + when :hard then 'HardDelete' + when :soft then 'SoftDelete' + when :recycle then 'MoveToDeletedItems' + else 'MoveToDeletedItems' + end + end - def build_deleted_occurrences(occurrences) - occurrences.collect { |a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text] } - end + def build_deleted_occurrences(occurrences) + occurrences.collect { |a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text] } + end - def build_modified_occurrences(occurrences) - {}.tap do |h| - occurrences.collect do |a| - elems = a[:occurrence][:elems] + def build_modified_occurrences(occurrences) + {}.tap do |h| + occurrences.collect do |a| + elems = a[:occurrence][:elems] - h[DateTime.parse(elems.find { |e| e[:original_start] }[:original_start][:text])] = { - start: elems.find { |e| e[:start] }[:start][:text], - end: elems.find { |e| e[:end] }[:end][:text] - } + h[DateTime.parse(elems.find { |e| e[:original_start] }[:original_start][:text])] = { + start: elems.find { |e| e[:start] }[:start][:text], + end: elems.find { |e| e[:end] }[:end][:text] + } + end + end end - end - end - def build_mailbox_user(mbox_ews) - MailboxUser.new(ews, mbox_ews) - end + def build_mailbox_user(mbox_ews) + MailboxUser.new(ews, mbox_ews) + end - def build_mailbox_users(users) - return [] if users.nil? + def build_mailbox_users(users) + return [] if users.nil? - users.collect { |u| build_mailbox_user(u[:mailbox][:elems]) } - end + users.collect { |u| build_mailbox_user(u[:mailbox][:elems]) } + end - def build_attendees_users(users) - return [] if users.nil? + def build_attendees_users(users) + return [] if users.nil? - users.collect { |u| - u[:attendee][:elems].collect do |a| - build_mailbox_user(a[:mailbox][:elems]) if a[:mailbox] + users.collect { |u| + u[:attendee][:elems].collect do |a| + build_mailbox_user(a[:mailbox][:elems]) if a[:mailbox] + end + }.flatten.compact end - }.flatten.compact - end - def build_attachments(attachments) - return [] if attachments.nil? + def build_attachments(attachments) + return [] if attachments.nil? - attachments.collect do |att| - key = att.keys.first - class_by_name(key).new(self, att[key]) - end - end + attachments.collect do |att| + key = att.keys.first + class_by_name(key).new(self, att[key]) + end + end - def set_change_key(ck) - p = resolve_key_path(ews_item, key_paths[:change_key][0..-2]) - p[:change_key] = ck - end + def set_change_key(ck) + p = resolve_key_path(ews_item, key_paths[:change_key][0..-2]) + p[:change_key] = ck + end - # Handles the CreateItem call for Forward, ReplyTo, and ReplyAllTo - # It will handle the neccessary actions for adding attachments. - def dispatch_create_item!(msg) - if msg.has_attachments? - draft = msg.draft - msg.draft = true - resp = validate_created_item(ews.create_item(msg.to_ews)) - msg.file_attachments.each do |f| - next unless f.is_a?(File) - - resp.add_file_attachment(f) - end - if draft - resp.submit_attachments! - resp - else - resp.submit! - end - else - resp = ews.create_item(msg.to_ews) - validate_created_item resp - end - end + # Handles the CreateItem call for Forward, ReplyTo, and ReplyAllTo + # It will handle the neccessary actions for adding attachments. + def dispatch_create_item!(msg) + if msg.has_attachments? + draft = msg.draft + msg.draft = true + resp = validate_created_item(ews.create_item(msg.to_ews)) + msg.file_attachments.each do |f| + next unless f.is_a?(File) + + resp.add_file_attachment(f) + end + if draft + resp.submit_attachments! + resp + else + resp.submit! + end + else + resp = ews.create_item(msg.to_ews) + validate_created_item resp + end + end - # validate the CreateItem response. - # @return [Boolean, Item] returns true if items is empty and status is - # "Success" if items is not empty it will return the first Item since - # we are only dealing with single items here. - # @raise EwsCreateItemError on failure - def validate_created_item(response) - msg = response.response_messages[0] + # validate the CreateItem response. + # @return [Boolean, Item] returns true if items is empty and status is + # "Success" if items is not empty it will return the first Item since + # we are only dealing with single items here. + # @raise EwsCreateItemError on failure + def validate_created_item(response) + msg = response.response_messages[0] - raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}" unless msg.status == 'Success' + raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}" unless msg.status == 'Success' - msg.items.empty? || parse_created_item(msg.items.first) - end + msg.items.empty? || parse_created_item(msg.items.first) + end - def parse_created_item(msg) - mtype = msg.keys.first - class_by_name(mtype).new(ews, msg[mtype]) + def parse_created_item(msg) + mtype = msg.keys.first + class_by_name(mtype).new(ews, msg[mtype]) + end + end end end end diff --git a/lib/ews/types/item_attachment.rb b/lib/ews/types/item_attachment.rb index ac057c07..704c8b59 100644 --- a/lib/ews/types/item_attachment.rb +++ b/lib/ews/types/item_attachment.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,64 +16,69 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class ItemAttachment < Attachment - ITEM_ATTACH_KEY_PATHS = { - item: [:item], - message: [:message], - calendar_item: [:calendar_item], - contact: [:contact], - task: [:task], - meeting_message: [:meeting_message], - meeting_request: [:meeting_request], - meeting_response: [:meeting_response], - meeting_cancellation: [:meeting_cancellation] - } +module Viewpoint + module EWS + module Types + class ItemAttachment < Attachment + ITEM_ATTACH_KEY_PATHS = { + item: [:item], + message: [:message], + calendar_item: [:calendar_item], + contact: [:contact], + task: [:task], + meeting_message: [:meeting_message], + meeting_request: [:meeting_request], + meeting_response: [:meeting_response], + meeting_cancellation: [:meeting_cancellation] + } - ITEM_ATTACH_KEY_TYPES = { - message: :build_message, - calendar_item: :build_calendar_item, - contact: :build_contact, - task: :build_task, - meeting_message: :build_meeting_message, - meeting_request: :build_meeting_request, - meeting_response: :build_meeting_response, - meeting_cancellation: :build_meeting_cancellation - } + ITEM_ATTACH_KEY_TYPES = { + message: :build_message, + calendar_item: :build_calendar_item, + contact: :build_contact, + task: :build_task, + meeting_message: :build_meeting_message, + meeting_request: :build_meeting_request, + meeting_response: :build_meeting_response, + meeting_cancellation: :build_meeting_cancellation + } - ITEM_ATTACH_KEY_ALIAS = {} + ITEM_ATTACH_KEY_ALIAS = {} - def get_all_properties! - resp = ews.get_attachment attachment_ids: [id] - @ews_item.merge!(parse_response(resp)) - end + def get_all_properties! + resp = ews.get_attachment attachment_ids: [id] + @ews_item.merge!(parse_response(resp)) + end - private + private - def self.method_missing(method, *args, &block) - if method.to_s =~ /^build_(.+)$/ - class_by_name(::Regexp.last_match(1)).new(ews, args[0]) - else - super - end - end + def self.method_missing(method, *args, &block) + if method.to_s =~ /^build_(.+)$/ + class_by_name(::Regexp.last_match(1)).new(ews, args[0]) + else + super + end + end - def key_paths - super.merge(ITEM_ATTACH_KEY_PATHS) - end + def key_paths + super.merge(ITEM_ATTACH_KEY_PATHS) + end - def key_types - super.merge(ITEM_ATTACH_KEY_TYPES) - end + def key_types + super.merge(ITEM_ATTACH_KEY_TYPES) + end - def key_alias - super.merge(ITEM_ATTACH_KEY_ALIAS) - end + def key_alias + super.merge(ITEM_ATTACH_KEY_ALIAS) + end - def parse_response(resp) - raise EwsError, "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + def parse_response(resp) + raise EwsError, + "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' - resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge) + resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge) + end + end end end end diff --git a/lib/ews/types/item_field_uri_map.rb b/lib/ews/types/item_field_uri_map.rb index 2ec0e888..21dedbe9 100644 --- a/lib/ews/types/item_field_uri_map.rb +++ b/lib/ews/types/item_field_uri_map.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/ews/types/mailbox_user.rb b/lib/ews/types/mailbox_user.rb index 71e017d8..6d6fe062 100644 --- a/lib/ews/types/mailbox_user.rb +++ b/lib/ews/types/mailbox_user.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,136 +16,140 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - # This represents a Mailbox object in the Exchange data store - # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs - # @todo Design a Class method that resolves to an Array of MailboxUsers - class MailboxUser - include Viewpoint::EWS - include Viewpoint::EWS::Types - - MAILBOX_KEY_PATHS = { - name: [:name], - email_address: [:email_address] - } - MAILBOX_KEY_TYPES = {} - MAILBOX_KEY_ALIAS = { - email: :email_address - } - - def initialize(ews, mbox_user) - @ews = ews - @ews_item = mbox_user - simplify! - end - - def out_of_office_settings - mailbox = { address: email_address } - resp = @ews.get_user_oof_settings(mailbox) - ewsi = resp.response.clone - ewsi.delete(:response_message) - return OutOfOffice.new(self, ewsi) - s = resp[:oof_settings] - @oof_state = s[:oof_state][:text] - @oof_ext_audience = s[:external_audience][:text] - @oof_start = DateTime.parse(s[:duration][:start_time][:text]) - @oof_end = DateTime.parse(s[:duration][:end_time][:text]) - @oof_internal_reply = s[:internal_reply][:message][:text] - @oof_external_reply = s[:internal_reply][:message][:text] - true - end - - # Get information about when the user with the given email address is available. - # @param [String] email_address The email address of the person to find availability for. - # @param [DateTime] start_time The start of the time range to check as an xs:dateTime. - # @param [DateTime] end_time The end of the time range to check as an xs:dateTime. - # @see http://msdn.microsoft.com/en-us/library/aa563800(v=exchg.140) - def get_user_availability(email_address, start_time, end_time) - opts = { - mailbox_data: [{ email: { address: email_address } }], - free_busy_view_options: { - time_window: { start_time: start_time, end_time: end_time } +module Viewpoint + module EWS + module Types + # This represents a Mailbox object in the Exchange data store + # @see http://msdn.microsoft.com/en-us/library/aa565036.aspx MSDN docs + # @todo Design a Class method that resolves to an Array of MailboxUsers + class MailboxUser + include Viewpoint::EWS + include Viewpoint::EWS::Types + + MAILBOX_KEY_PATHS = { + name: [:name], + email_address: [:email_address] + } + MAILBOX_KEY_TYPES = {} + MAILBOX_KEY_ALIAS = { + email: :email_address } - } - resp = Viewpoint::EWS::EWS.instance.ews.get_user_availability(opts) - unless resp.status == 'Success' - raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" - end - - resp.items - end - - # Adds one or more delegates to a principal's mailbox and sets specific access permissions - # @see http://msdn.microsoft.com/en-us/library/bb856527.aspx - # - # @param [String,MailboxUser] delegate_email The user you would like to give delegate access to. - # This can either be a simple String e-mail address or you can pass in a MailboxUser object. - # @param [Hash] permissions A hash of folder type keys and permission type values. An example - # would be {:calendar_folder_permission_level => 'Editor'}. Possible keys are: - # :calendar_folder_permission_level, :tasks_folder_permission_level, :inbox_folder_permission_level - # :contacts_folder_permission_level, :notes_folder_permission_level, :journal_folder_permission_level - # and possible values are: None/Editor/Reviewer/Author/Custom - # @return [true] This method either returns true or raises an error with the message - # as to why this operation did not succeed. - def add_delegate!(delegate_email, permissions) - # Use a new hash so the passed hash is not modified in case we are in a loop. - # Thanks to Markus Roberts for pointing this out. - formatted_perms = {} - # Modify permissions so we can pass it to the builders - permissions.each_pair do |k, v| - formatted_perms[k] = { text: v } - end - - resp = Viewpoint::EWS::EWS.instance.ews.add_delegate(email_address, delegate_email, formatted_perms) - unless resp.status == 'Success' - raise EwsError, "Could not add delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" - end - - true - end - - def update_delegate!(delegate_email, permissions) - # Modify permissions so we can pass it to the builders - formatted_perms = {} - permissions.each_pair do |k, v| - formatted_perms[k] = { text: v } - end - resp = Viewpoint::EWS::EWS.instance.ews.update_delegate(email_address, delegate_email, formatted_perms) - unless resp.status == 'Success' - raise EwsError, "Could not update delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" + def initialize(ews, mbox_user) + @ews = ews + @ews_item = mbox_user + simplify! + end + + def out_of_office_settings + mailbox = { address: email_address } + resp = @ews.get_user_oof_settings(mailbox) + ewsi = resp.response.clone + ewsi.delete(:response_message) + return OutOfOffice.new(self, ewsi) + s = resp[:oof_settings] + @oof_state = s[:oof_state][:text] + @oof_ext_audience = s[:external_audience][:text] + @oof_start = DateTime.parse(s[:duration][:start_time][:text]) + @oof_end = DateTime.parse(s[:duration][:end_time][:text]) + @oof_internal_reply = s[:internal_reply][:message][:text] + @oof_external_reply = s[:internal_reply][:message][:text] + true + end + + # Get information about when the user with the given email address is available. + # @param [String] email_address The email address of the person to find availability for. + # @param [DateTime] start_time The start of the time range to check as an xs:dateTime. + # @param [DateTime] end_time The end of the time range to check as an xs:dateTime. + # @see http://msdn.microsoft.com/en-us/library/aa563800(v=exchg.140) + def get_user_availability(email_address, start_time, end_time) + opts = { + mailbox_data: [{ email: { address: email_address } }], + free_busy_view_options: { + time_window: { start_time: start_time, end_time: end_time } + } + } + resp = Viewpoint::EWS::EWS.instance.ews.get_user_availability(opts) + unless resp.status == 'Success' + raise EwsError, "GetUserAvailability produced an error: #{resp.code}: #{resp.message}" + end + + resp.items + end + + # Adds one or more delegates to a principal's mailbox and sets specific access permissions + # @see http://msdn.microsoft.com/en-us/library/bb856527.aspx + # + # @param [String,MailboxUser] delegate_email The user you would like to give delegate access to. + # This can either be a simple String e-mail address or you can pass in a MailboxUser object. + # @param [Hash] permissions A hash of folder type keys and permission type values. An example + # would be {:calendar_folder_permission_level => 'Editor'}. Possible keys are: + # :calendar_folder_permission_level, :tasks_folder_permission_level, :inbox_folder_permission_level + # :contacts_folder_permission_level, :notes_folder_permission_level, :journal_folder_permission_level + # and possible values are: None/Editor/Reviewer/Author/Custom + # @return [true] This method either returns true or raises an error with the message + # as to why this operation did not succeed. + def add_delegate!(delegate_email, permissions) + # Use a new hash so the passed hash is not modified in case we are in a loop. + # Thanks to Markus Roberts for pointing this out. + formatted_perms = {} + # Modify permissions so we can pass it to the builders + permissions.each_pair do |k, v| + formatted_perms[k] = { text: v } + end + + resp = Viewpoint::EWS::EWS.instance.ews.add_delegate(email_address, delegate_email, formatted_perms) + unless resp.status == 'Success' + raise EwsError, "Could not add delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" + end + + true + end + + def update_delegate!(delegate_email, permissions) + # Modify permissions so we can pass it to the builders + formatted_perms = {} + permissions.each_pair do |k, v| + formatted_perms[k] = { text: v } + end + + resp = Viewpoint::EWS::EWS.instance.ews.update_delegate(email_address, delegate_email, formatted_perms) + unless resp.status == 'Success' + raise EwsError, "Could not update delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" + end + + true + end + + def get_delegate_info + Viewpoint::EWS::EWS.instance.ews.get_delegate(email_address) + # if(resp.status == 'Success') + # return true + # else + # raise EwsError, "Could not update delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" + # end + end + + private + + def simplify! + @ews_item = @ews_item.each_with_object({}) { |o, m| + m[o.keys.first] = o.values.first[:text] + } + end + + def key_paths + @key_paths ||= super.merge(MAILBOX_KEY_PATHS) + end + + def key_types + @key_types ||= super.merge(MAILBOX_KEY_TYPES) + end + + def key_alias + @key_alias ||= super.merge(MAILBOX_KEY_ALIAS) + end end - - true - end - - def get_delegate_info - Viewpoint::EWS::EWS.instance.ews.get_delegate(email_address) - # if(resp.status == 'Success') - # return true - # else - # raise EwsError, "Could not update delegate access for user #{delegate_email}: #{resp.code}, #{resp.message}" - # end - end - - private - - def simplify! - @ews_item = @ews_item.each_with_object({}) { |o, m| - m[o.keys.first] = o.values.first[:text] - } - end - - def key_paths - @key_paths ||= super.merge(MAILBOX_KEY_PATHS) - end - - def key_types - @key_types ||= super.merge(MAILBOX_KEY_TYPES) - end - - def key_alias - @key_alias ||= super.merge(MAILBOX_KEY_ALIAS) end end end diff --git a/lib/ews/types/meeting_cancellation.rb b/lib/ews/types/meeting_cancellation.rb index d2cbc7c4..889dd4e1 100644 --- a/lib/ews/types/meeting_cancellation.rb +++ b/lib/ews/types/meeting_cancellation.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class MeetingCancellation - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class MeetingCancellation + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/meeting_message.rb b/lib/ews/types/meeting_message.rb index c66c78c4..fac3aa0f 100644 --- a/lib/ews/types/meeting_message.rb +++ b/lib/ews/types/meeting_message.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class MeetingMessage - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class MeetingMessage + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/meeting_request.rb b/lib/ews/types/meeting_request.rb index 4b7200b1..d10ba9ac 100644 --- a/lib/ews/types/meeting_request.rb +++ b/lib/ews/types/meeting_request.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class MeetingRequest - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class MeetingRequest + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/meeting_response.rb b/lib/ews/types/meeting_response.rb index 1df6692a..1c7264d0 100644 --- a/lib/ews/types/meeting_response.rb +++ b/lib/ews/types/meeting_response.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class MeetingResponse - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class MeetingResponse + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/message.rb b/lib/ews/types/message.rb index 26b2f733..34617f0b 100644 --- a/lib/ews/types/message.rb +++ b/lib/ews/types/message.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class Message - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class Message + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/modified_event.rb b/lib/ews/types/modified_event.rb index 6e2434da..8b611a83 100644 --- a/lib/ews/types/modified_event.rb +++ b/lib/ews/types/modified_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,26 +16,30 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class ModifiedEvent < Event - MODIFIED_EVENT_KEY_PATHS = {} +module Viewpoint + module EWS + module Types + class ModifiedEvent < Event + MODIFIED_EVENT_KEY_PATHS = {} - MODIFIED_EVENT_KEY_TYPES = {} + MODIFIED_EVENT_KEY_TYPES = {} - MODIFIED_EVENT_KEY_ALIAS = {} + MODIFIED_EVENT_KEY_ALIAS = {} - private + private - def key_paths - @key_paths ||= super.merge MODIFIED_EVENT_KEY_PATHS - end + def key_paths + @key_paths ||= super.merge MODIFIED_EVENT_KEY_PATHS + end - def key_types - @key_types ||= super.merge MODIFIED_EVENT_KEY_TYPES - end + def key_types + @key_types ||= super.merge MODIFIED_EVENT_KEY_TYPES + end - def key_alias - @key_alias ||= super.merge MODIFIED_EVENT_KEY_ALIAS + def key_alias + @key_alias ||= super.merge MODIFIED_EVENT_KEY_ALIAS + end + end end end end diff --git a/lib/ews/types/moved_event.rb b/lib/ews/types/moved_event.rb index 5a178ee7..e096cf3d 100644 --- a/lib/ews/types/moved_event.rb +++ b/lib/ews/types/moved_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,30 +16,34 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class MovedEvent < Event - MOVED_EVENT_KEY_PATHS = { - old_item_id: %i[old_item_id attribs], - old_folder_id: %i[old_folder_id attribs], - old_parent_folder_id: %i[old_parent_folder_id attribs] - } +module Viewpoint + module EWS + module Types + class MovedEvent < Event + MOVED_EVENT_KEY_PATHS = { + old_item_id: %i[old_item_id attribs], + old_folder_id: %i[old_folder_id attribs], + old_parent_folder_id: %i[old_parent_folder_id attribs] + } - MOVED_EVENT_KEY_TYPES = {} + MOVED_EVENT_KEY_TYPES = {} - MOVED_EVENT_KEY_ALIAS = {} + MOVED_EVENT_KEY_ALIAS = {} - private + private - def key_paths - @key_paths ||= super.merge MOVED_EVENT_KEY_PATHS - end + def key_paths + @key_paths ||= super.merge MOVED_EVENT_KEY_PATHS + end - def key_types - @key_types ||= super.merge MOVED_EVENT_KEY_TYPES - end + def key_types + @key_types ||= super.merge MOVED_EVENT_KEY_TYPES + end - def key_alias - @key_alias ||= super.merge MOVED_EVENT_KEY_ALIAS + def key_alias + @key_alias ||= super.merge MOVED_EVENT_KEY_ALIAS + end + end end end end diff --git a/lib/ews/types/new_mail_event.rb b/lib/ews/types/new_mail_event.rb index d62e51d0..e0c4db8d 100644 --- a/lib/ews/types/new_mail_event.rb +++ b/lib/ews/types/new_mail_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,7 +16,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class NewMailEvent < Event +module Viewpoint + module EWS + module Types + class NewMailEvent < Event + end + end end end diff --git a/lib/ews/types/out_of_office.rb b/lib/ews/types/out_of_office.rb index a67a026c..08f955b1 100644 --- a/lib/ews/types/out_of_office.rb +++ b/lib/ews/types/out_of_office.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,129 +16,133 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - OOF_KEY_PATHS = { - enabled?: %i[oof_settings oof_state], - scheduled?: %i[oof_settings oof_state], - duration: %i[oof_settings duration] - } - - OOF_KEY_TYPES = { - enabled?: ->(str) { str == :enabled }, - scheduled?: ->(str) { str == :scheduled }, - duration: ->(hsh) { hsh[:start_time]..hsh[:end_time] } - } - - OOF_KEY_ALIAS = {} - - # This represents OutOfOffice settings - # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx - class OutOfOffice - include Viewpoint::EWS - include Viewpoint::EWS::Types - - attr_reader :user - - # @param [MailboxUser] user - # @param [Hash] ews_item - def initialize(user, ews_item) - @ews = user.ews - @user = user - @ews_item = ews_item - @changed = false - simplify! - end - - def changed? - @changed - end - - def save! - return true unless changed? - - opts = { mailbox: { address: user.email_address } }.merge(@ews_item[:oof_settings]) - resp = @ews.set_user_oof_settings(opts) - raise SaveFailed, "Could not save #{self.class}. #{resp.code}: #{resp.message}" unless resp.success? - - @changed = false - true - end - - def enable - return true if enabled? - - @changed = true - @ews_item[:oof_settings][:oof_state] = :enabled - end - - def disable - return true unless enabled? || scheduled? - - @changed = true - @ews_item[:oof_settings][:oof_state] = :disabled - end - - # Schedule an out of office. - # @param [DateTime] start_time - # @param [DateTime] end_time - def schedule(start_time, end_time) - @changed = true - @ews_item[:oof_settings][:oof_state] = :scheduled - set_duration start_time, end_time - end - - # Specify a duration for this Out Of Office setting - # @param [DateTime] start_time - # @param [DateTime] end_time - def set_duration(start_time, end_time) - @changed = true - @ews_item[:oof_settings][:duration][:start_time] = start_time - @ews_item[:oof_settings][:duration][:end_time] = end_time - end - - # A message to send to internal users - # @param [String] message - def internal_reply=(message) - @changed = true - @ews_item[:oof_settings][:internal_reply] = message - end - - # A message to send to external users - # @param [String] message - def external_reply=(message) - @changed = true - @ews_item[:oof_settings][:external_reply] = message - end - - private - - def key_paths - @key_paths ||= super.merge(OOF_KEY_PATHS) - end - - def key_types - @key_types ||= super.merge(OOF_KEY_TYPES) - end - - def key_alias - @key_alias ||= super.merge(OOF_KEY_ALIAS) - end - - def simplify! - oof_settings = @ews_item[:oof_settings][:elems].inject(:merge) - oof_settings[:oof_state] = oof_settings[:oof_state][:text].downcase.to_sym - oof_settings[:external_audience] = oof_settings[:external_audience][:text] - if oof_settings[:duration] - dur = oof_settings[:duration][:elems].inject(:merge) - oof_settings[:duration] = { - start_time: DateTime.iso8601(dur[:start_time][:text]), - end_time: DateTime.iso8601(dur[:end_time][:text]) - } +module Viewpoint + module EWS + module Types + OOF_KEY_PATHS = { + enabled?: %i[oof_settings oof_state], + scheduled?: %i[oof_settings oof_state], + duration: %i[oof_settings duration] + } + + OOF_KEY_TYPES = { + enabled?: ->(str) { str == :enabled }, + scheduled?: ->(str) { str == :scheduled }, + duration: ->(hsh) { hsh[:start_time]..hsh[:end_time] } + } + + OOF_KEY_ALIAS = {} + + # This represents OutOfOffice settings + # @see http://msdn.microsoft.com/en-us/library/aa563465.aspx + class OutOfOffice + include Viewpoint::EWS + include Viewpoint::EWS::Types + + attr_reader :user + + # @param [MailboxUser] user + # @param [Hash] ews_item + def initialize(user, ews_item) + @ews = user.ews + @user = user + @ews_item = ews_item + @changed = false + simplify! + end + + def changed? + @changed + end + + def save! + return true unless changed? + + opts = { mailbox: { address: user.email_address } }.merge(@ews_item[:oof_settings]) + resp = @ews.set_user_oof_settings(opts) + raise SaveFailed, "Could not save #{self.class}. #{resp.code}: #{resp.message}" unless resp.success? + + @changed = false + true + end + + def enable + return true if enabled? + + @changed = true + @ews_item[:oof_settings][:oof_state] = :enabled + end + + def disable + return true unless enabled? || scheduled? + + @changed = true + @ews_item[:oof_settings][:oof_state] = :disabled + end + + # Schedule an out of office. + # @param [DateTime] start_time + # @param [DateTime] end_time + def schedule(start_time, end_time) + @changed = true + @ews_item[:oof_settings][:oof_state] = :scheduled + set_duration start_time, end_time + end + + # Specify a duration for this Out Of Office setting + # @param [DateTime] start_time + # @param [DateTime] end_time + def set_duration(start_time, end_time) + @changed = true + @ews_item[:oof_settings][:duration][:start_time] = start_time + @ews_item[:oof_settings][:duration][:end_time] = end_time + end + + # A message to send to internal users + # @param [String] message + def internal_reply=(message) + @changed = true + @ews_item[:oof_settings][:internal_reply] = message + end + + # A message to send to external users + # @param [String] message + def external_reply=(message) + @changed = true + @ews_item[:oof_settings][:external_reply] = message + end + + private + + def key_paths + @key_paths ||= super.merge(OOF_KEY_PATHS) + end + + def key_types + @key_types ||= super.merge(OOF_KEY_TYPES) + end + + def key_alias + @key_alias ||= super.merge(OOF_KEY_ALIAS) + end + + def simplify! + oof_settings = @ews_item[:oof_settings][:elems].inject(:merge) + oof_settings[:oof_state] = oof_settings[:oof_state][:text].downcase.to_sym + oof_settings[:external_audience] = oof_settings[:external_audience][:text] + if oof_settings[:duration] + dur = oof_settings[:duration][:elems].inject(:merge) + oof_settings[:duration] = { + start_time: DateTime.iso8601(dur[:start_time][:text]), + end_time: DateTime.iso8601(dur[:end_time][:text]) + } + end + oof_settings[:internal_reply] = oof_settings[:internal_reply][:elems][0][:message][:text] || '' + oof_settings[:external_reply] = oof_settings[:external_reply][:elems][0][:message][:text] || '' + @ews_item[:oof_settings] = oof_settings + @ews_item[:allow_external_oof] = @ews_item[:allow_external_oof][:text] + end end - oof_settings[:internal_reply] = oof_settings[:internal_reply][:elems][0][:message][:text] || '' - oof_settings[:external_reply] = oof_settings[:external_reply][:elems][0][:message][:text] || '' - @ews_item[:oof_settings] = oof_settings - @ews_item[:allow_external_oof] = @ews_item[:allow_external_oof][:text] end end end diff --git a/lib/ews/types/post_item.rb b/lib/ews/types/post_item.rb index 3f2b63ac..9b5cfd39 100644 --- a/lib/ews/types/post_item.rb +++ b/lib/ews/types/post_item.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class PostItem - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item + +module Viewpoint + module EWS + module Types + class PostItem + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item + end + end end end diff --git a/lib/ews/types/search_folder.rb b/lib/ews/types/search_folder.rb index 5be18b13..0bd99d2f 100644 --- a/lib/ews/types/search_folder.rb +++ b/lib/ews/types/search_folder.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class SearchFolder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::GenericFolder + +module Viewpoint + module EWS + module Types + class SearchFolder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::GenericFolder + end + end end end diff --git a/lib/ews/types/status_event.rb b/lib/ews/types/status_event.rb index 01086d3e..cd3b7bdb 100644 --- a/lib/ews/types/status_event.rb +++ b/lib/ews/types/status_event.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek @@ -15,20 +16,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -module Viewpoint::EWS::Types - class StatusEvent - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item +module Viewpoint + module EWS + module Types + class StatusEvent + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item - STATUS_EVENT_KEY_PATHS = { - watermark: %i[watermark text] - } + STATUS_EVENT_KEY_PATHS = { + watermark: %i[watermark text] + } - private + private - def key_paths - @key_paths ||= STATUS_EVENT_KEY_PATHS + def key_paths + @key_paths ||= STATUS_EVENT_KEY_PATHS + end + end end end end diff --git a/lib/ews/types/task.rb b/lib/ews/types/task.rb index 8d3b861a..32ac7f3e 100644 --- a/lib/ews/types/task.rb +++ b/lib/ews/types/task.rb @@ -1,41 +1,46 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class Task - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::Item - TASK_KEY_PATHS = { - complete?: %i[is_complete text], - recurring?: %i[is_recurring text], - start_date: %i[start_date text], - due_date: %i[end_date text], - reminder_due_by: %i[reminder_due_by text], - reminder?: %i[reminder_is_set text], - percent_complete: %i[percent_complete text], - status: %i[status text] - } +module Viewpoint + module EWS + module Types + class Task + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::Item - TASK_KEY_TYPES = { - recurring?: ->(str) { str.downcase == 'true' }, - complete?: ->(str) { str.downcase == 'true' }, - reminder?: ->(str) { str.downcase == 'true' }, - percent_complete: ->(str) { str.to_i } - } - TASK_KEY_ALIAS = {} + TASK_KEY_PATHS = { + complete?: %i[is_complete text], + recurring?: %i[is_recurring text], + start_date: %i[start_date text], + due_date: %i[end_date text], + reminder_due_by: %i[reminder_due_by text], + reminder?: %i[reminder_is_set text], + percent_complete: %i[percent_complete text], + status: %i[status text] + } - private + TASK_KEY_TYPES = { + recurring?: ->(str) { str.downcase == 'true' }, + complete?: ->(str) { str.downcase == 'true' }, + reminder?: ->(str) { str.downcase == 'true' }, + percent_complete: ->(str) { str.to_i } + } + TASK_KEY_ALIAS = {} - def key_paths - super.merge(TASK_KEY_PATHS) - end + private - def key_types - super.merge(TASK_KEY_TYPES) - end + def key_paths + super.merge(TASK_KEY_PATHS) + end + + def key_types + super.merge(TASK_KEY_TYPES) + end - def key_alias - super.merge(TASK_KEY_ALIAS) + def key_alias + super.merge(TASK_KEY_ALIAS) + end + end end end end diff --git a/lib/ews/types/tasks_folder.rb b/lib/ews/types/tasks_folder.rb index b63d7ed1..aa9e5ed7 100644 --- a/lib/ews/types/tasks_folder.rb +++ b/lib/ews/types/tasks_folder.rb @@ -1,30 +1,35 @@ # frozen_string_literal: true -module Viewpoint::EWS::Types - class TasksFolder - include Viewpoint::EWS - include Viewpoint::EWS::Types - include Viewpoint::EWS::Types::GenericFolder - # Creates a new task - # @param attributes [Hash] Parameters of the task. Some example attributes are listed below. - # @option attributes :subject [String] - # @option attributes :start_date [Time] - # @option attributes :due_date [Time] - # @option attributes :reminder_due_by [Time] - # @option attributes :reminder_is_set [Boolean] - # @return [Task] - # @see Template::Task - def create_item(attributes) - template = Viewpoint::EWS::Template::Task.new attributes - template.saved_item_folder_id = { id: id, change_key: change_key } - rm = ews.create_item(template.to_ews_create).response_messages.first - if rm && rm.success? - Task.new ews, rm.items.first[:task][:elems].first - else - raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm +module Viewpoint + module EWS + module Types + class TasksFolder + include Viewpoint::EWS + include Viewpoint::EWS::Types + include Viewpoint::EWS::Types::GenericFolder - raise EwsCreateItemError, 'Could not create item in folder.' + # Creates a new task + # @param attributes [Hash] Parameters of the task. Some example attributes are listed below. + # @option attributes :subject [String] + # @option attributes :start_date [Time] + # @option attributes :due_date [Time] + # @option attributes :reminder_due_by [Time] + # @option attributes :reminder_is_set [Boolean] + # @return [Task] + # @see Template::Task + def create_item(attributes) + template = Viewpoint::EWS::Template::Task.new attributes + template.saved_item_folder_id = { id: id, change_key: change_key } + rm = ews.create_item(template.to_ews_create).response_messages.first + if rm && rm.success? + Task.new ews, rm.items.first[:task][:elems].first + else + raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm + raise EwsCreateItemError, 'Could not create item in folder.' + + end + end end end end diff --git a/lib/viewpoint.rb b/lib/viewpoint.rb index 606196c6..4d858f62 100644 --- a/lib/viewpoint.rb +++ b/lib/viewpoint.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/logging.rb b/lib/viewpoint/logging.rb index 95e4c495..956b950b 100644 --- a/lib/viewpoint/logging.rb +++ b/lib/viewpoint/logging.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/logging/config.rb b/lib/viewpoint/logging/config.rb index ca2aa08b..2e87dbee 100644 --- a/lib/viewpoint/logging/config.rb +++ b/lib/viewpoint/logging/config.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/lib/viewpoint/string_utils.rb b/lib/viewpoint/string_utils.rb index 75641665..54460517 100644 --- a/lib/viewpoint/string_utils.rb +++ b/lib/viewpoint/string_utils.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # This file is part of Viewpoint; the Ruby library for Microsoft Exchange Web Services. # # Copyright © 2011 Dan Wanek diff --git a/spec/ews/ews_client_spec.rb b/spec/ews/ews_client_spec.rb index f4e87c54..b542adec 100644 --- a/spec/ews/ews_client_spec.rb +++ b/spec/ews/ews_client_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'spec_helper' describe Viewpoint::EWSClient do diff --git a/spec/ews/types/calendar_item_spec.rb b/spec/ews/types/calendar_item_spec.rb index 38d0cf57..cabf103c 100644 --- a/spec/ews/types/calendar_item_spec.rb +++ b/spec/ews/types/calendar_item_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'spec_helper' describe Viewpoint::EWS::Types::CalendarItem do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fd230f0d..39186369 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + $: << File.dirname(__FILE__) + '/../lib/' require 'viewpoint' require 'viewpoint/logging/config' diff --git a/spec/unit/dodgy_file_spec.rb b/spec/unit/dodgy_file_spec.rb index 56ae5ca8..68c80b08 100644 --- a/spec/unit/dodgy_file_spec.rb +++ b/spec/unit/dodgy_file_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe 'Tolerant parsing' do diff --git a/spec/unit/ews_folder_operations_spec.rb b/spec/unit/ews_folder_operations_spec.rb index b5ce0836..2afac837 100644 --- a/spec/unit/ews_folder_operations_spec.rb +++ b/spec/unit/ews_folder_operations_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe 'Operations on Exchange Data Services' do diff --git a/spec/unit/ews_parser_spec.rb b/spec/unit/ews_parser_spec.rb index 8021ca42..2dd8a07a 100644 --- a/spec/unit/ews_parser_spec.rb +++ b/spec/unit/ews_parser_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe 'Exchange Response Parser Functionality' do diff --git a/spec/unit/ews_rooms_operations_spec.rb b/spec/unit/ews_rooms_operations_spec.rb index 607ce158..68d5acda 100644 --- a/spec/unit/ews_rooms_operations_spec.rb +++ b/spec/unit/ews_rooms_operations_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe 'Room operations on Exchange Data Services' do diff --git a/spec/unit/ews_soap_free_busy_response_spec.rb b/spec/unit/ews_soap_free_busy_response_spec.rb index cfda704a..2c137825 100644 --- a/spec/unit/ews_soap_free_busy_response_spec.rb +++ b/spec/unit/ews_soap_free_busy_response_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe Viewpoint::EWS::SOAP::EwsSoapFreeBusyResponse do diff --git a/spec/unit/folder_accessors_spec.rb b/spec/unit/folder_accessors_spec.rb index ddd8b098..6ec031c7 100644 --- a/spec/unit/folder_accessors_spec.rb +++ b/spec/unit/folder_accessors_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' module ResponseObjects diff --git a/spec/unit/item_accessors_spec.rb b/spec/unit/item_accessors_spec.rb index afac9514..221bba01 100644 --- a/spec/unit/item_accessors_spec.rb +++ b/spec/unit/item_accessors_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' module ResponseObjects diff --git a/spec/unit/mailbox_accessors_spec.rb b/spec/unit/mailbox_accessors_spec.rb index 5d0572af..185dd517 100644 --- a/spec/unit/mailbox_accessors_spec.rb +++ b/spec/unit/mailbox_accessors_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe Viewpoint::EWS::MailboxAccessors do diff --git a/spec/unit/meeting_accessors_spec.rb b/spec/unit/meeting_accessors_spec.rb index cf9f5d27..79d17219 100644 --- a/spec/unit/meeting_accessors_spec.rb +++ b/spec/unit/meeting_accessors_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../spec_helper' describe Viewpoint::EWS::MeetingAccessors do diff --git a/spec/unit/soap/builders/ews_builder_spec.rb b/spec/unit/soap/builders/ews_builder_spec.rb index 6f7650b8..5fde0f72 100644 --- a/spec/unit/soap/builders/ews_builder_spec.rb +++ b/spec/unit/soap/builders/ews_builder_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require_relative '../../../spec_helper' describe Viewpoint::EWS::SOAP::EwsBuilder do diff --git a/spec/viewpoint/string_utils_spec.rb b/spec/viewpoint/string_utils_spec.rb index f606ea15..c829b606 100644 --- a/spec/viewpoint/string_utils_spec.rb +++ b/spec/viewpoint/string_utils_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'spec_helper' describe Viewpoint::StringUtils do diff --git a/spec/xml_matcher.rb b/spec/xml_matcher.rb index 244637b9..0a9db048 100644 --- a/spec/xml_matcher.rb +++ b/spec/xml_matcher.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + RSpec::Matchers.define :match_xml do |expected| match do |actual| compare_xml(actual, expected) diff --git a/viewpoint.gemspec b/viewpoint.gemspec index 6648d24e..5a7b30b3 100644 --- a/viewpoint.gemspec +++ b/viewpoint.gemspec @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'date' version = File.read(File.expand_path('VERSION', __dir__)).strip From d5f3eea50098c3e89a55f15b3639c8b0db10950e Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:57:42 +0000 Subject: [PATCH 05/12] Lint: fix Void/EmptyElse/TernaryParentheses/BlockDelimiters by hand --- lib/ews/folder_accessors.rb | 18 ++++++++++++------ lib/ews/soap.rb | 6 +++--- lib/ews/soap/builders/ews_builder.rb | 1 - lib/ews/types/calendar_item.rb | 2 -- lib/ews/types/file_attachment.rb | 6 ++++-- lib/ews/types/generic_folder.rb | 2 +- lib/ews/types/item.rb | 12 ++++++++---- lib/ews/types/item_attachment.rb | 6 ++++-- spec/unit/ews_rooms_operations_spec.rb | 4 ++-- spec/unit/mailbox_accessors_spec.rb | 4 ++-- spec/unit/meeting_accessors_spec.rb | 12 ++++++------ 11 files changed, 42 insertions(+), 31 deletions(-) diff --git a/lib/ews/folder_accessors.rb b/lib/ews/folder_accessors.rb index b0f2e432..2371d8ab 100644 --- a/lib/ews/folder_accessors.rb +++ b/lib/ews/folder_accessors.rb @@ -153,8 +153,10 @@ def find_folders_args(opts) # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp def find_folders_parser(resp) - raise EwsFolderNotFound, - "Could not retrieve folders. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + unless resp.status == 'Success' + raise EwsFolderNotFound, + "Could not retrieve folders. #{resp.code}: #{resp.message}" + end folders = resp.response_message[:elems][:root_folder][:elems][0][:folders][:elems] return [] if folders.nil? @@ -191,8 +193,10 @@ def get_folder_args(folder_id, opts) # @param [Viewpoint::EWS::SOAP::EwsSoapResponse] resp def get_folder_parser(resp) - raise EwsFolderNotFound, - "Could not retrieve folder. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + unless resp.status == 'Success' + raise EwsFolderNotFound, + "Could not retrieve folder. #{resp.code}: #{resp.message}" + end f = resp.response_message[:elems][:folders][:elems][0] ftype = f.keys.first @@ -216,8 +220,10 @@ def sync_folders_args(opts) def sync_folders_parser(resp) rmsg = resp.response_messages[0] - raise EwsError, - "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + unless rmsg.success? + raise EwsError, + "Could not synchronize folders. #{rmsg.response_code}: #{rmsg.message_text}" + end rhash = {} rhash[:all_synced] = rmsg.includes_last_folder_in_range? diff --git a/lib/ews/soap.rb b/lib/ews/soap.rb index a0912998..8358c970 100644 --- a/lib/ews/soap.rb +++ b/lib/ews/soap.rb @@ -23,9 +23,9 @@ module EWS module SOAP # CONSTANTS - NS_SOAP = 'soap'.freeze - NS_EWS_TYPES = 't'.freeze - NS_EWS_MESSAGES = 'm'.freeze + NS_SOAP = 'soap' + NS_EWS_TYPES = 't' + NS_EWS_MESSAGES = 'm' NAMESPACES = { "xmlns:#{NS_SOAP}" => 'http://schemas.xmlsoap.org/soap/envelope/', "xmlns:#{NS_EWS_TYPES}" => 'http://schemas.microsoft.com/exchange/services/2006/types', diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index 1d12972a..5ddb6dd6 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -380,7 +380,6 @@ def routing_type!(type) end def mailbox_type!(type) - Standard nbuild[NS_EWS_TYPES].MailboxType(type) end diff --git a/lib/ews/types/calendar_item.rb b/lib/ews/types/calendar_item.rb index 6e209cd6..838f6835 100644 --- a/lib/ews/types/calendar_item.rb +++ b/lib/ews/types/calendar_item.rb @@ -100,8 +100,6 @@ def update_item!(updates, options = {}) } item_updates << { set_item_field: field.merge(calendar_item: { sub_elements: item_attributes }) } - else - # Ignore unknown attribute end end diff --git a/lib/ews/types/file_attachment.rb b/lib/ews/types/file_attachment.rb index 15509632..8738b44c 100644 --- a/lib/ews/types/file_attachment.rb +++ b/lib/ews/types/file_attachment.rb @@ -53,8 +53,10 @@ def key_alias end def parse_response(resp) - raise EwsError, - "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + unless resp.status == 'Success' + raise EwsError, + "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" + end resp.response_message[:elems][:attachments][:elems][0][:file_attachment][:elems].inject(&:merge) end diff --git a/lib/ews/types/generic_folder.rb b/lib/ews/types/generic_folder.rb index cef18711..9709fd8c 100644 --- a/lib/ews/types/generic_folder.rb +++ b/lib/ews/types/generic_folder.rb @@ -241,7 +241,7 @@ def push_subscribe(url, evtypes = [:all], watermark = nil, status_frequency = ni # Check if there is a subscription for this folder. # @return [Boolean] Are we subscribed to this folder? def subscribed? - (@subscription_id.nil? or @watermark.nil?) ? false : true + !@subscription_id.nil? && !@watermark.nil? end # Unsubscribe this folder from further Exchange events. diff --git a/lib/ews/types/item.rb b/lib/ews/types/item.rb index 7f30631b..d06949ff 100644 --- a/lib/ews/types/item.rb +++ b/lib/ews/types/item.rb @@ -112,8 +112,10 @@ def delete!(deltype = :hard, opts = {}) resp = @ews.delete_item(opts) rmsg = resp.response_messages[0] - raise EwsError, - "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success? + unless rmsg.success? + raise EwsError, + "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}" + end true end @@ -331,8 +333,10 @@ def get_item_args(opts) def get_item_parser(resp) rm = resp.response_messages[0] - raise EwsError, - "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" unless rm.status == 'Success' + unless rm.status == 'Success' + raise EwsError, + "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}" + end rm.items[0].values.first end diff --git a/lib/ews/types/item_attachment.rb b/lib/ews/types/item_attachment.rb index 704c8b59..0e3ec02b 100644 --- a/lib/ews/types/item_attachment.rb +++ b/lib/ews/types/item_attachment.rb @@ -73,8 +73,10 @@ def key_alias end def parse_response(resp) - raise EwsError, - "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" unless resp.status == 'Success' + unless resp.status == 'Success' + raise EwsError, + "Could not retrieve #{self.class}. #{resp.code}: #{resp.message}" + end resp.response_message[:elems][:attachments][:elems][0][:item_attachment][:elems].inject(&:merge) end diff --git a/spec/unit/ews_rooms_operations_spec.rb b/spec/unit/ews_rooms_operations_spec.rb index 68d5acda..a325ffd9 100644 --- a/spec/unit/ews_rooms_operations_spec.rb +++ b/spec/unit/ews_rooms_operations_spec.rb @@ -20,10 +20,10 @@ end it 'generates GetRoomLists XML' do - expect(@ews).to receive(:do_soap_request) do |request_document| + expect(@ews).to receive(:do_soap_request) { |request_document| doc = request_document.to_s.gsub(/>\s+/, '>') expect(doc).to eq load_soap('get_room_lists', :request) - end.and_return(double(:resp)) + }.and_return(double(:resp)) @ews.get_room_lists end end diff --git a/spec/unit/mailbox_accessors_spec.rb b/spec/unit/mailbox_accessors_spec.rb index 185dd517..ca60fbbc 100644 --- a/spec/unit/mailbox_accessors_spec.rb +++ b/spec/unit/mailbox_accessors_spec.rb @@ -35,9 +35,9 @@ context '#get_user_availability' do it 'should care about timezones' do - expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| + expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) { |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body//t:TimeZone').to_s).to eq timezone_request - end + } .and_return(double(:resp, status: 'Success')) ecli.get_user_availability( diff --git a/spec/unit/meeting_accessors_spec.rb b/spec/unit/meeting_accessors_spec.rb index 79d17219..fc616e98 100644 --- a/spec/unit/meeting_accessors_spec.rb +++ b/spec/unit/meeting_accessors_spec.rb @@ -30,9 +30,9 @@ end it 'should form valid accept item request' do - expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| + expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) { |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end + } .and_return(double(:resp, status: 'Success')) ecli.accept_meeting(default_opts) @@ -55,9 +55,9 @@ end it 'should form valid accept item request' do - expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| + expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) { |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end + } .and_return(double(:resp, status: 'success')) ecli.decline_meeting(default_opts) @@ -80,9 +80,9 @@ end it 'should form valid accept item request' do - expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) do |request_document| + expect_any_instance_of(Viewpoint::EWS::SOAP::ExchangeWebService).to receive(:do_soap_request) { |request_document| expect(request_document.at_xpath('//soap:Envelope/soap:Body').to_s).to eq create_item_request - end + } .and_return(double(:resp, status: 'success')) ecli.tentatively_accept_meeting(default_opts) From 5325107928c5d6c098f1412b53bf4e17973a17f4 Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:58:15 +0000 Subject: [PATCH 06/12] Lint: spec_helper modernization (LOAD_PATH, interpolation, RSpec config.include) --- spec/spec_helper.rb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 39186369..f27d8cf3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,21 +1,12 @@ # frozen_string_literal: true -$: << File.dirname(__FILE__) + '/../lib/' +$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib/" require 'viewpoint' require 'viewpoint/logging/config' require 'ostruct' require 'turn/autorun' require_relative 'xml_matcher' -RSpec.configure do |config| - config.mock_with :rspec do |mocks| - mocks.yield_receiver_to_any_instance_implementation_blocks = false - end - config.raise_errors_for_deprecations! -end - -Turn.config.format = :outline - module SpecHelper def specdir File.dirname(__FILE__) @@ -26,4 +17,12 @@ def load_soap(name, type) end end -include SpecHelper +RSpec.configure do |config| + config.include SpecHelper + config.mock_with :rspec do |mocks| + mocks.yield_receiver_to_any_instance_implementation_blocks = false + end + config.raise_errors_for_deprecations! +end + +Turn.config.format = :outline From 5d553a45bcbe18d92be819da77e2b2da261000ed Mon Sep 17 00:00:00 2001 From: Peter Cai <222655+pcai@users.noreply.github.com> Date: Thu, 10 Sep 2026 15:58:41 +0000 Subject: [PATCH 07/12] Lint: hand-fix AndOr/SafeNavigation/SymbolProc/HashMethods/regexp/exception --- Rakefile | 4 +--- lib/ews/folder_accessors.rb | 2 +- lib/ews/impersonation.rb | 2 +- lib/ews/mailbox_accessors.rb | 2 +- lib/ews/message_accessors.rb | 4 ++-- lib/ews/soap/builders/ews_builder.rb | 6 +++--- lib/ews/soap/ews_soap_free_busy_response.rb | 2 +- lib/ews/soap/ews_soap_response.rb | 2 +- lib/ews/soap/exchange_data_services.rb | 2 +- lib/ews/soap/exchange_web_service.rb | 4 ++-- lib/ews/soap/response_message.rb | 2 +- .../soap/responses/find_item_response_message.rb | 2 +- .../soap/responses/get_events_response_message.rb | 2 +- .../send_notification_response_message.rb | 2 +- lib/ews/templates/calendar_item.rb | 2 +- lib/ews/types.rb | 2 +- lib/ews/types/attachment.rb | 2 +- lib/ews/types/calendar_folder.rb | 2 +- lib/ews/types/calendar_item.rb | 2 +- lib/ews/types/folder.rb | 2 +- lib/ews/types/generic_folder.rb | 10 +++++----- lib/ews/types/item.rb | 6 +++--- lib/ews/types/task.rb | 2 +- lib/ews/types/tasks_folder.rb | 2 +- lib/viewpoint/string_utils.rb | 14 +++++++------- 25 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Rakefile b/Rakefile index 45433e62..edd00655 100644 --- a/Rakefile +++ b/Rakefile @@ -30,9 +30,7 @@ end def up_min_version f = File.open('VERSION', 'r+') ver = f.readline.chomp - v_arr = ver.split(/\./).map { |v| - v.to_i - } + v_arr = ver.split(/\./).map(&:to_i) v_arr[2] += 1 ver = v_arr.join('.') f.rewind diff --git a/lib/ews/folder_accessors.rb b/lib/ews/folder_accessors.rb index 2371d8ab..b44d6391 100644 --- a/lib/ews/folder_accessors.rb +++ b/lib/ews/folder_accessors.rb @@ -230,7 +230,7 @@ def sync_folders_parser(resp) rhash[:sync_state] = rmsg.sync_state rmsg.changes.each do |c| ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) + rhash[ctype] = [] unless rhash.key?(ctype) if ctype == :delete rhash[ctype] << c[ctype][:elems][0][:folder_id][:attribs] else diff --git a/lib/ews/impersonation.rb b/lib/ews/impersonation.rb index 4ddc9130..efb5bde3 100644 --- a/lib/ews/impersonation.rb +++ b/lib/ews/impersonation.rb @@ -17,7 +17,7 @@ module EWS # you can add any other string, it will be converted into xml tag on soap request # @param address [String] an address to include to requests for impersonation def set_impersonation(connecting_type, address) - unless ConnectingSID.has_value? connecting_type or connecting_type.is_a? String + unless ConnectingSID.value?(connecting_type) || connecting_type.is_a?(String) raise EwsBadArgumentError, "Not a proper connecting method: #{connecting_type.class}" end diff --git a/lib/ews/mailbox_accessors.rb b/lib/ews/mailbox_accessors.rb index 70fcc54a..cedb1508 100644 --- a/lib/ews/mailbox_accessors.rb +++ b/lib/ews/mailbox_accessors.rb @@ -66,7 +66,7 @@ def get_user_availability(emails, opts) private def get_user_availability_args(emails, opts) - unless opts.has_key?(:start_time) && opts.has_key?(:end_time) && opts.has_key?(:requested_view) + unless opts.key?(:start_time) && opts.key?(:end_time) && opts.key?(:requested_view) raise EwsBadArgumentError, 'You must specify a start_time, end_time and requested_view.' end diff --git a/lib/ews/message_accessors.rb b/lib/ews/message_accessors.rb index 984438e6..49fc3380 100644 --- a/lib/ews/message_accessors.rb +++ b/lib/ews/message_accessors.rb @@ -50,12 +50,12 @@ def send_message(opts = {}, &block) resp = parse_create_item(ews.create_item(msg.to_ews)) msg.draft = true msg.file_attachments.each do |f| - next unless f.is_a?(File) or f.is_a?(Tempfile) + next unless f.is_a?(File) || f.is_a?(Tempfile) resp.add_file_attachment(f) end msg.inline_attachments.each do |f| - next unless f.is_a?(File) or f.is_a?(Tempfile) + next unless f.is_a?(File) || f.is_a?(Tempfile) resp.add_inline_attachment(f) end diff --git a/lib/ews/soap/builders/ews_builder.rb b/lib/ews/soap/builders/ews_builder.rb index 5ddb6dd6..a970b9c5 100644 --- a/lib/ews/soap/builders/ews_builder.rb +++ b/lib/ews/soap/builders/ews_builder.rb @@ -131,7 +131,7 @@ def item_shape!(item_shape) @nbuild[NS_EWS_MESSAGES].ItemShape { @nbuild.parent.default_namespace = @default_ns base_shape!(item_shape[:base_shape]) - mime_content!(item_shape[:include_mime_content]) if item_shape.has_key?(:include_mime_content) + mime_content!(item_shape[:include_mime_content]) if item_shape.key?(:include_mime_content) body_type!(item_shape[:body_type]) if item_shape[:body_type] additional_properties!(item_shape[:additional_properties]) if item_shape[:additional_properties] } @@ -474,7 +474,7 @@ def time_zone!(zone) # Request all known time_zones from server def get_server_time_zones!(get_time_zone_options) nbuild[NS_EWS_MESSAGES].GetServerTimeZones('ReturnFullTimeZoneData' => get_time_zone_options[:full]) do - if get_time_zone_options[:ids] && get_time_zone_options[:ids].any? + if get_time_zone_options[:ids]&.any? nbuild[NS_EWS_MESSAGES].Ids do get_time_zone_options[:ids].each do |id| nbuild[NS_EWS_TYPES].Id id @@ -1309,7 +1309,7 @@ def parent_namespace(node) end def set_version_header!(version) - return unless version && !(version == 'none') + return unless version && version != 'none' nbuild[NS_EWS_TYPES].RequestServerVersion { |x| x.parent['Version'] = version diff --git a/lib/ews/soap/ews_soap_free_busy_response.rb b/lib/ews/soap/ews_soap_free_busy_response.rb index 34eaf15c..3eacc284 100644 --- a/lib/ews/soap/ews_soap_free_busy_response.rb +++ b/lib/ews/soap/ews_soap_free_busy_response.rb @@ -96,7 +96,7 @@ def simplify! # @return [Object, nil] def guard_hash(hsh, keys) key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) + return nil unless hsh.is_a?(Hash) && hsh.key?(key) if keys.empty? hsh[key] diff --git a/lib/ews/soap/ews_soap_response.rb b/lib/ews/soap/ews_soap_response.rb index e92917bd..568ac836 100644 --- a/lib/ews/soap/ews_soap_response.rb +++ b/lib/ews/soap/ews_soap_response.rb @@ -87,7 +87,7 @@ def simplify! # @return [Object, nil] def guard_hash(hsh, keys) key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) + return nil unless hsh.is_a?(Hash) && hsh.key?(key) if keys.empty? hsh[key] diff --git a/lib/ews/soap/exchange_data_services.rb b/lib/ews/soap/exchange_data_services.rb index 5ae7eb6e..1ac666e2 100644 --- a/lib/ews/soap/exchange_data_services.rb +++ b/lib/ews/soap/exchange_data_services.rb @@ -714,7 +714,7 @@ def expand_dl(opts) # @see http://msdn.microsoft.com/en-us/library/aa565998.aspx def resolve_names(opts) opts = opts.clone - fcd = opts.has_key?(:full_contact_data) ? opts[:full_contact_data] : true + fcd = opts.key?(:full_contact_data) ? opts[:full_contact_data] : true req = build_soap! { |type, builder| unless type == :header builder.nbuild.ResolveNames { |x| diff --git a/lib/ews/soap/exchange_web_service.rb b/lib/ews/soap/exchange_web_service.rb index 16f1430c..ebea6b6c 100644 --- a/lib/ews/soap/exchange_web_service.rb +++ b/lib/ews/soap/exchange_web_service.rb @@ -232,13 +232,13 @@ def parse_soap_response(soapmsg, opts = {}) # default value for the operation. def validate_param(opts, key, required, default_val = nil) if required - raise EwsBadArgumentError, "Required parameter(#{key}) not passed." unless opts.has_key?(key) + raise EwsBadArgumentError, "Required parameter(#{key}) not passed." unless opts.key?(key) opts[key] else raise EwsBadArgumentError, 'Default value not supplied.' unless default_val - opts.has_key?(key) ? opts[key] : default_val + opts.key?(key) ? opts[key] : default_val end end diff --git a/lib/ews/soap/response_message.rb b/lib/ews/soap/response_message.rb index 94879267..f45124d4 100644 --- a/lib/ews/soap/response_message.rb +++ b/lib/ews/soap/response_message.rb @@ -57,7 +57,7 @@ def items def safe_hash_access(hsh, keys) key = keys.shift - return nil unless hsh.is_a?(Hash) && hsh.has_key?(key) + return nil unless hsh.is_a?(Hash) && hsh.key?(key) if keys.empty? hsh[key] diff --git a/lib/ews/soap/responses/find_item_response_message.rb b/lib/ews/soap/responses/find_item_response_message.rb index f6a50ef3..59b4e451 100644 --- a/lib/ews/soap/responses/find_item_response_message.rb +++ b/lib/ews/soap/responses/find_item_response_message.rb @@ -57,7 +57,7 @@ def groups private def attrib(key) - return nil unless root.has_key?(:attribs) + return nil unless root.key?(:attribs) root[:attribs][key] end diff --git a/lib/ews/soap/responses/get_events_response_message.rb b/lib/ews/soap/responses/get_events_response_message.rb index 5782072e..f2148c38 100644 --- a/lib/ews/soap/responses/get_events_response_message.rb +++ b/lib/ews/soap/responses/get_events_response_message.rb @@ -45,7 +45,7 @@ def more_events? end def events - notification[3..-1] + notification[3..] end end end diff --git a/lib/ews/soap/responses/send_notification_response_message.rb b/lib/ews/soap/responses/send_notification_response_message.rb index 33bcb1f7..00fe33f2 100644 --- a/lib/ews/soap/responses/send_notification_response_message.rb +++ b/lib/ews/soap/responses/send_notification_response_message.rb @@ -48,7 +48,7 @@ def more_events? def events @events ||= - notification[3..-1].collect { |ev| + notification[3..].collect { |ev| type = ev.keys.first klass = Viewpoint::EWS::Types.const_get(camel_case(type)) klass.new(nil, ev[type]) diff --git a/lib/ews/templates/calendar_item.rb b/lib/ews/templates/calendar_item.rb index 9ea2e311..83c3e47b 100644 --- a/lib/ews/templates/calendar_item.rb +++ b/lib/ews/templates/calendar_item.rb @@ -32,7 +32,7 @@ def to_ews_create(opts = {}) structure[:message_disposition] = (draft ? 'SaveOnly' : 'SendAndSaveCopy') # options structure[:send_meeting_invitations] = - (opts.has_key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') + (opts.key?(:send_meeting_invitations) ? opts[:send_meeting_invitations] : 'SendToNone') if saved_item_folder_id structure[:saved_item_folder_id] = if saved_item_folder_id.is_a?(Hash) diff --git a/lib/ews/types.rb b/lib/ews/types.rb index 2ea2c791..7871ee9f 100644 --- a/lib/ews/types.rb +++ b/lib/ews/types.rb @@ -139,7 +139,7 @@ def resolve_key_path(hsh, path) k = path.first return hsh[k] if path.length == 1 - resolve_key_path(hsh[k], path[1..-1]) + resolve_key_path(hsh[k], path[1..]) end def method_keys diff --git a/lib/ews/types/attachment.rb b/lib/ews/types/attachment.rb index 69d9f344..3451c7ff 100644 --- a/lib/ews/types/attachment.rb +++ b/lib/ews/types/attachment.rb @@ -41,7 +41,7 @@ class Attachment ATTACH_KEY_TYPES = { is_inline?: ->(str) { str.downcase == 'true' }, last_modified_type: ->(str) { DateTime.parse(str) }, - size: ->(str) { str.to_i }, + size: lambda(&:to_i), content_id: :fix_content_id } diff --git a/lib/ews/types/calendar_folder.rb b/lib/ews/types/calendar_folder.rb index bc5f1a50..af9a7cfe 100644 --- a/lib/ews/types/calendar_folder.rb +++ b/lib/ews/types/calendar_folder.rb @@ -50,7 +50,7 @@ def create_item(attributes, to_ews_create_opts = {}) template = Viewpoint::EWS::Template::CalendarItem.new attributes template.saved_item_folder_id = { id: id, change_key: change_key } rm = ews.create_item(template.to_ews_create(to_ews_create_opts)).response_messages.first - if rm && rm.success? + if rm&.success? CalendarItem.new ews, rm.items.first[:calendar_item][:elems].first else raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm diff --git a/lib/ews/types/calendar_item.rb b/lib/ews/types/calendar_item.rb index 838f6835..f160c473 100644 --- a/lib/ews/types/calendar_item.rb +++ b/lib/ews/types/calendar_item.rb @@ -111,7 +111,7 @@ def update_item!(updates, options = {}) options[:send_meeting_invitations_or_cancellations] || 'SendToNone' data[:item_changes] = [{ item_id: item_id, updates: item_updates }] rm = ews.update_item(data).response_messages.first - if rm && rm.success? + if rm&.success? get_all_properties! self else diff --git a/lib/ews/types/folder.rb b/lib/ews/types/folder.rb index a7d2c293..c1427ae3 100644 --- a/lib/ews/types/folder.rb +++ b/lib/ews/types/folder.rb @@ -12,7 +12,7 @@ class Folder unread_count: %i[unread_count text] } FOLDER_KEY_TYPES = { - unread_count: ->(str) { str.to_i } + unread_count: lambda(&:to_i) } FOLDER_KEY_ALIAS = {} diff --git a/lib/ews/types/generic_folder.rb b/lib/ews/types/generic_folder.rb index 9709fd8c..e40a7ed1 100644 --- a/lib/ews/types/generic_folder.rb +++ b/lib/ews/types/generic_folder.rb @@ -40,8 +40,8 @@ module GenericFolder } GFOLDER_KEY_TYPES = { - total_count: ->(str) { str.to_i }, - child_folder_count: ->(str) { str.to_i } + total_count: lambda(&:to_i), + child_folder_count: lambda(&:to_i) } GFOLDER_KEY_ALIAS = { @@ -170,7 +170,7 @@ def available_categories # :change_key is returned. # See: http://msdn.microsoft.com/en-us/library/aa565609.aspx def sync_items!(sync_state = nil, sync_amount = 256, _sync_all = false, opts = {}) - item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : { base_shape: :default } + item_shape = opts.key?(:item_shape) ? opts.delete(:item_shape) : { base_shape: :default } sync_state ||= @sync_state resp = ews.sync_folder_items item_shape: item_shape, @@ -184,7 +184,7 @@ def sync_items!(sync_state = nil, sync_amount = 256, _sync_all = false, opts = { rhash = {} rmsg.changes.each do |c| ctype = c.keys.first - rhash[ctype] = [] unless rhash.has_key?(ctype) + rhash[ctype] = [] unless rhash.key?(ctype) if %i[delete read_flag_change].include?(ctype) rhash[ctype] << c[ctype][:elems][0][:item_id][:attribs] else @@ -297,7 +297,7 @@ def key_alias def simplify! @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| key = i.keys.first - if o.has_key?(key) + if o.key?(key) if o[key].is_a?(Array) o[key] << i[key] else diff --git a/lib/ews/types/item.rb b/lib/ews/types/item.rb index d06949ff..f80f93fa 100644 --- a/lib/ews/types/item.rb +++ b/lib/ews/types/item.rb @@ -52,7 +52,7 @@ def init_simple_item(ews, id, change_key = nil, parent = nil) } ITEM_KEY_TYPES = { - size: ->(str) { str.to_i }, + size: lambda(&:to_i), date_time_sent: ->(str) { DateTime.parse(str) }, date_time_created: ->(str) { DateTime.parse(str) }, last_modified_time: ->(str) { DateTime.parse(str) }, @@ -293,11 +293,11 @@ def update_is_read_status(read) end def simplify! - return unless @ews_item.has_key?(:elems) + return unless @ews_item.key?(:elems) @ews_item = @ews_item[:elems].each_with_object({}) do |i, o| key = i.keys.first - if o.has_key?(key) + if o.key?(key) if o[key].is_a?(Array) o[key] << i[key] else diff --git a/lib/ews/types/task.rb b/lib/ews/types/task.rb index 32ac7f3e..12a77d81 100644 --- a/lib/ews/types/task.rb +++ b/lib/ews/types/task.rb @@ -23,7 +23,7 @@ class Task recurring?: ->(str) { str.downcase == 'true' }, complete?: ->(str) { str.downcase == 'true' }, reminder?: ->(str) { str.downcase == 'true' }, - percent_complete: ->(str) { str.to_i } + percent_complete: lambda(&:to_i) } TASK_KEY_ALIAS = {} diff --git a/lib/ews/types/tasks_folder.rb b/lib/ews/types/tasks_folder.rb index aa9e5ed7..44c50935 100644 --- a/lib/ews/types/tasks_folder.rb +++ b/lib/ews/types/tasks_folder.rb @@ -21,7 +21,7 @@ def create_item(attributes) template = Viewpoint::EWS::Template::Task.new attributes template.saved_item_folder_id = { id: id, change_key: change_key } rm = ews.create_item(template.to_ews_create).response_messages.first - if rm && rm.success? + if rm&.success? Task.new ews, rm.items.first[:task][:elems].first else raise EwsCreateItemError, "Could not create item in folder. #{rm.code}: #{rm.message_text}" if rm diff --git a/lib/viewpoint/string_utils.rb b/lib/viewpoint/string_utils.rb index 54460517..f3f2065c 100644 --- a/lib/viewpoint/string_utils.rb +++ b/lib/viewpoint/string_utils.rb @@ -17,18 +17,18 @@ # limitations under the License. module Viewpoint - class StringFormatException < ::Exception; end + class StringFormatException < ::StandardError; end # Collection of utility methods for working with Strings module StringUtils DURATION_RE = / (?P) - ((?\d+)W)? - ((?\d+)D)? + (?:(?\d+)W)? + (?:(?\d+)D)? (?