viewpoint 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -8
  3. data/lib/ews/calendar_accessors.rb +37 -33
  4. data/lib/ews/connection.rb +151 -124
  5. data/lib/ews/connection_helper.rb +36 -33
  6. data/lib/ews/convert_accessors.rb +58 -54
  7. data/lib/ews/errors.rb +59 -53
  8. data/lib/ews/ews_client.rb +92 -79
  9. data/lib/ews/exceptions/exceptions.rb +61 -61
  10. data/lib/ews/folder_accessors.rb +235 -234
  11. data/lib/ews/impersonation.rb +29 -23
  12. data/lib/ews/item_accessors.rb +215 -213
  13. data/lib/ews/mailbox_accessors.rb +82 -79
  14. data/lib/ews/meeting_accessors.rb +38 -31
  15. data/lib/ews/message_accessors.rb +83 -81
  16. data/lib/ews/push_subscription_accessors.rb +29 -27
  17. data/lib/ews/room_accessors.rb +48 -46
  18. data/lib/ews/roomlist_accessors.rb +47 -45
  19. data/lib/ews/soap/builders/ews_builder.rb +1186 -1188
  20. data/lib/ews/soap/ews_response.rb +68 -73
  21. data/lib/ews/soap/ews_soap_availability_response.rb +57 -57
  22. data/lib/ews/soap/ews_soap_free_busy_response.rb +115 -117
  23. data/lib/ews/soap/ews_soap_response.rb +99 -101
  24. data/lib/ews/soap/ews_soap_room_response.rb +45 -45
  25. data/lib/ews/soap/ews_soap_roomlist_response.rb +45 -46
  26. data/lib/ews/soap/exchange_availability.rb +54 -52
  27. data/lib/ews/soap/exchange_data_services.rb +693 -711
  28. data/lib/ews/soap/exchange_notification.rb +123 -128
  29. data/lib/ews/soap/exchange_synchronization.rb +82 -82
  30. data/lib/ews/soap/exchange_time_zones.rb +41 -44
  31. data/lib/ews/soap/exchange_user_configuration.rb +30 -27
  32. data/lib/ews/soap/exchange_web_service.rb +237 -233
  33. data/lib/ews/soap/parsers/ews_parser.rb +46 -42
  34. data/lib/ews/soap/parsers/ews_sax_document.rb +63 -58
  35. data/lib/ews/soap/response_message.rb +69 -68
  36. data/lib/ews/soap/responses/create_attachment_response_message.rb +45 -45
  37. data/lib/ews/soap/responses/create_item_response_message.rb +26 -25
  38. data/lib/ews/soap/responses/find_item_response_message.rb +76 -78
  39. data/lib/ews/soap/responses/get_events_response_message.rb +52 -51
  40. data/lib/ews/soap/responses/send_notification_response_message.rb +53 -51
  41. data/lib/ews/soap/responses/subscribe_response_message.rb +37 -34
  42. data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +38 -35
  43. data/lib/ews/soap/responses/sync_folder_items_response_message.rb +38 -35
  44. data/lib/ews/soap.rb +27 -26
  45. data/lib/ews/templates/calendar_item.rb +64 -60
  46. data/lib/ews/templates/forward_item.rb +19 -17
  47. data/lib/ews/templates/message.rb +61 -67
  48. data/lib/ews/templates/reply_to_item.rb +20 -18
  49. data/lib/ews/templates/task.rb +55 -55
  50. data/lib/ews/types/attachment.rb +75 -74
  51. data/lib/ews/types/attendee.rb +27 -25
  52. data/lib/ews/types/calendar_folder.rb +60 -44
  53. data/lib/ews/types/calendar_item.rb +134 -116
  54. data/lib/ews/types/contact.rb +11 -5
  55. data/lib/ews/types/contacts_folder.rb +10 -5
  56. data/lib/ews/types/copied_event.rb +47 -48
  57. data/lib/ews/types/created_event.rb +22 -20
  58. data/lib/ews/types/deleted_event.rb +22 -20
  59. data/lib/ews/types/distribution_list.rb +11 -5
  60. data/lib/ews/types/event.rb +60 -59
  61. data/lib/ews/types/export_items_response_message.rb +54 -50
  62. data/lib/ews/types/file_attachment.rb +63 -61
  63. data/lib/ews/types/folder.rb +58 -57
  64. data/lib/ews/types/free_busy_changed_event.rb +22 -20
  65. data/lib/ews/types/generic_folder.rb +348 -372
  66. data/lib/ews/types/item.rb +401 -397
  67. data/lib/ews/types/item_attachment.rb +87 -80
  68. data/lib/ews/types/item_field_uri_map.rb +201 -200
  69. data/lib/ews/types/mailbox_user.rb +146 -154
  70. data/lib/ews/types/meeting_cancellation.rb +11 -5
  71. data/lib/ews/types/meeting_message.rb +11 -5
  72. data/lib/ews/types/meeting_request.rb +11 -5
  73. data/lib/ews/types/meeting_response.rb +11 -5
  74. data/lib/ews/types/message.rb +11 -5
  75. data/lib/ews/types/modified_event.rb +43 -45
  76. data/lib/ews/types/moved_event.rb +47 -48
  77. data/lib/ews/types/new_mail_event.rb +22 -20
  78. data/lib/ews/types/out_of_office.rb +145 -144
  79. data/lib/ews/types/post_item.rb +11 -5
  80. data/lib/ews/types/search_folder.rb +10 -5
  81. data/lib/ews/types/status_event.rb +37 -36
  82. data/lib/ews/types/task.rb +39 -33
  83. data/lib/ews/types/tasks_folder.rb +32 -22
  84. data/lib/ews/types.rb +134 -139
  85. data/lib/viewpoint/logging/config.rb +19 -19
  86. data/lib/viewpoint/logging.rb +23 -17
  87. data/lib/viewpoint/string_utils.rb +31 -32
  88. data/lib/viewpoint.rb +18 -18
  89. metadata +82 -11
  90. data/Changelog.txt +0 -1004
@@ -1,447 +1,451 @@
1
- module Viewpoint::EWS::Types
2
- module Item
3
- include Viewpoint::EWS
4
- include Viewpoint::EWS::Types
5
- include ItemFieldUriMap
6
-
7
- def self.included(klass)
8
- klass.extend ClassMethods
9
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Viewpoint
4
+ module EWS
5
+ module Types
6
+ # Item EWS data type.
7
+ module Item
8
+ include Viewpoint::EWS
9
+ include Viewpoint::EWS::Types
10
+ include ItemFieldUriMap
11
+
12
+ def self.included(klass)
13
+ klass.extend ClassMethods
14
+ end
10
15
 
11
- module ClassMethods
12
- def init_simple_item(ews, id, change_key = nil, parent = nil)
13
- ews_item = {item_id: {attribs: {id: id, change_key: change_key}}}
14
- self.new ews, ews_item, parent
15
- end
16
- end
16
+ # Class-level helpers for EWS item types.
17
+ module ClassMethods
18
+ def init_simple_item(ews, id, change_key = nil, parent = nil)
19
+ ews_item = { item_id: { attribs: { id: id, change_key: change_key } } }
20
+ new ews, ews_item, parent
21
+ end
22
+ end
17
23
 
18
- ITEM_KEY_PATHS = {
19
- item_id: [:item_id, :attribs],
20
- id: [:item_id, :attribs, :id],
21
- change_key: [:item_id, :attribs, :change_key],
22
- subject: [:subject, :text],
23
- sensitivity: [:sensitivity, :text],
24
- size: [:size, :text],
25
- date_time_sent: [:date_time_sent, :text],
26
- date_time_created: [:date_time_created, :text],
27
- last_modified_time: [:last_modified_time, :text],
28
- mime_content: [:mime_content, :text],
29
- has_attachments?:[:has_attachments, :text],
30
- is_associated?: [:is_associated, :text],
31
- is_read?: [:is_read, :text],
32
- is_draft?: [:is_draft, :text],
33
- is_submitted?: [:is_submitted, :text],
34
- conversation_id:[:conversation_id, :attribs, :id],
35
- categories: [:categories, :elems],
36
- internet_message_id:[:internet_message_id, :text],
37
- internet_message_headers:[:internet_message_headers, :elems],
38
- sender: [:sender, :elems, 0, :mailbox, :elems],
39
- from: [:from, :elems, 0, :mailbox, :elems],
40
- to_recipients: [:to_recipients, :elems],
41
- cc_recipients: [:cc_recipients, :elems],
42
- attachments: [:attachments, :elems],
43
- importance: [:importance, :text],
44
- conversation_index: [:conversation_index, :text],
45
- conversation_topic: [:conversation_topic, :text],
46
- body_type: [:body, :attribs, :body_type],
47
- body: [:body, :text]
48
- }
49
-
50
- ITEM_KEY_TYPES = {
51
- size: ->(str){str.to_i},
52
- date_time_sent: ->(str){DateTime.parse(str)},
53
- date_time_created: ->(str){DateTime.parse(str)},
54
- last_modified_time: ->(str){DateTime.parse(str)},
55
- has_attachments?: ->(str){str.downcase == 'true'},
56
- is_associated?: ->(str){str.downcase == 'true'},
57
- is_read?: ->(str){str.downcase == 'true'},
58
- is_draft?: ->(str){str.downcase == 'true'},
59
- is_submitted?: ->(str){str.downcase == 'true'},
60
- categories: ->(obj){obj.collect{|s| s[:string][:text]}},
61
- internet_message_headers: ->(obj){obj.collect{|h|
62
- {h[:internet_message_header][:attribs][:header_name] =>
63
- h[:internet_message_header][:text]} } },
64
- sender: :build_mailbox_user,
65
- from: :build_mailbox_user,
66
- to_recipients: :build_mailbox_users,
67
- cc_recipients: :build_mailbox_users,
68
- attachments: :build_attachments,
69
- }
70
-
71
- ITEM_KEY_ALIAS = {
72
- :read? => :is_read?,
73
- :draft? => :is_draft?,
74
- :submitted? => :is_submitted?,
75
- :associated? => :is_associated?,
76
- }
77
-
78
- attr_reader :ews_item, :parent
79
-
80
- # @param ews [SOAP::ExchangeWebService] the EWS reference
81
- # @param ews_item [Hash] the EWS parsed response document
82
- # @param parent [GenericFolder] an optional parent object
83
- def initialize(ews, ews_item, parent = nil)
84
- super(ews, ews_item)
85
- @parent = parent
86
- @body_type = false
87
- simplify!
88
- @new_file_attachments = []
89
- @new_item_attachments = []
90
- @new_inline_attachments = []
91
- end
24
+ ITEM_KEY_PATHS = {
25
+ item_id: %i[item_id attribs],
26
+ id: %i[item_id attribs id],
27
+ change_key: %i[item_id attribs change_key],
28
+ subject: %i[subject text],
29
+ sensitivity: %i[sensitivity text],
30
+ size: %i[size text],
31
+ date_time_sent: %i[date_time_sent text],
32
+ date_time_created: %i[date_time_created text],
33
+ last_modified_time: %i[last_modified_time text],
34
+ mime_content: %i[mime_content text],
35
+ has_attachments?: %i[has_attachments text],
36
+ is_associated?: %i[is_associated text],
37
+ is_read?: %i[is_read text],
38
+ is_draft?: %i[is_draft text],
39
+ is_submitted?: %i[is_submitted text],
40
+ conversation_id: %i[conversation_id attribs id],
41
+ categories: %i[categories elems],
42
+ internet_message_id: %i[internet_message_id text],
43
+ internet_message_headers: %i[internet_message_headers elems],
44
+ sender: [:sender, :elems, 0, :mailbox, :elems],
45
+ from: [:from, :elems, 0, :mailbox, :elems],
46
+ to_recipients: %i[to_recipients elems],
47
+ cc_recipients: %i[cc_recipients elems],
48
+ attachments: %i[attachments elems],
49
+ importance: %i[importance text],
50
+ conversation_index: %i[conversation_index text],
51
+ conversation_topic: %i[conversation_topic text],
52
+ body_type: %i[body attribs body_type],
53
+ body: %i[body text]
54
+ }.freeze
55
+
56
+ ITEM_KEY_TYPES = {
57
+ size: lambda(&:to_i),
58
+ date_time_sent: ->(str) { DateTime.parse(str) },
59
+ date_time_created: ->(str) { DateTime.parse(str) },
60
+ last_modified_time: ->(str) { DateTime.parse(str) },
61
+ has_attachments?: ->(str) { str.downcase == 'true' },
62
+ is_associated?: ->(str) { str.downcase == 'true' },
63
+ is_read?: ->(str) { str.downcase == 'true' },
64
+ is_draft?: ->(str) { str.downcase == 'true' },
65
+ is_submitted?: ->(str) { str.downcase == 'true' },
66
+ categories: ->(obj) { obj.collect { |s| s[:string][:text] } },
67
+ internet_message_headers: lambda { |obj|
68
+ obj.collect { |h|
69
+ { h[:internet_message_header][:attribs][:header_name] =>
70
+ h[:internet_message_header][:text] }
71
+ }
72
+ },
73
+ sender: :build_mailbox_user,
74
+ from: :build_mailbox_user,
75
+ to_recipients: :build_mailbox_users,
76
+ cc_recipients: :build_mailbox_users,
77
+ attachments: :build_attachments
78
+ }.freeze
79
+
80
+ ITEM_KEY_ALIAS = {
81
+ read?: :is_read?,
82
+ draft?: :is_draft?,
83
+ submitted?: :is_submitted?,
84
+ associated?: :is_associated?
85
+ }.freeze
86
+
87
+ attr_reader :ews_item, :parent
88
+
89
+ # @param ews [SOAP::ExchangeWebService] the EWS reference
90
+ # @param ews_item [Hash] the EWS parsed response document
91
+ # @param parent [GenericFolder] an optional parent object
92
+ def initialize(ews, ews_item, parent = nil)
93
+ super(ews, ews_item)
94
+ @parent = parent
95
+ @body_type = false
96
+ simplify!
97
+ @new_file_attachments = []
98
+ @new_item_attachments = []
99
+ @new_inline_attachments = []
100
+ end
92
101
 
93
- # Specify a body_type to fetch this item with if it hasn't already been fetched.
94
- # @param body_type [String, Symbol, FalseClass] must be :best, :text, or
95
- # :html. You can also set it to false to make it use the default.
96
- def default_body_type=(body_type)
97
- @body_type = body_type
98
- end
102
+ # Specify a body_type to fetch this item with if it hasn't already been fetched.
103
+ # @param body_type [String, Symbol, FalseClass] must be :best, :text, or
104
+ # :html. You can also set it to false to make it use the default.
105
+ def default_body_type=(body_type)
106
+ @body_type = body_type
107
+ end
99
108
 
100
- def delete!(deltype = :hard, opts = {})
101
- opts = {
102
- :delete_type => delete_type(deltype),
103
- :item_ids => [{:item_id => {:id => id}}]
104
- }.merge(opts)
109
+ def delete!(deltype = :hard, opts = {})
110
+ opts = {
111
+ delete_type: delete_type(deltype),
112
+ item_ids: [{ item_id: { id: id } }]
113
+ }.merge(opts)
114
+
115
+ resp = @ews.delete_item(opts)
116
+ rmsg = resp.response_messages[0]
117
+ unless rmsg.success?
118
+ raise EwsError,
119
+ "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}"
120
+ end
105
121
 
106
- resp = @ews.delete_item(opts)
107
- rmsg = resp.response_messages[0]
108
- unless rmsg.success?
109
- raise EwsError, "Could not delete #{self.class}. #{rmsg.response_code}: #{rmsg.message_text}"
110
- end
111
- true
112
- end
122
+ true
123
+ end
113
124
 
114
- def recycle!
115
- delete! :recycle
116
- end
125
+ def recycle!
126
+ delete! :recycle
127
+ end
117
128
 
118
- def get_all_properties!
119
- @ews_item = get_item(base_shape: 'AllProperties')
120
- simplify!
121
- end
129
+ def get_all_properties!
130
+ @ews_item = get_item(base_shape: 'AllProperties')
131
+ simplify!
132
+ end
122
133
 
123
- # Mark an item as read
124
- def mark_read!
125
- update_is_read_status true
126
- end
134
+ # Mark an item as read
135
+ def mark_read!
136
+ update_is_read_status true
137
+ end
127
138
 
128
- # Mark an item as unread
129
- def mark_unread!
130
- update_is_read_status false
131
- end
139
+ # Mark an item as unread
140
+ def mark_unread!
141
+ update_is_read_status false
142
+ end
132
143
 
133
- # Move this item to a new folder
134
- # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
135
- # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
136
- # @return [String] the new Id of the moved item
137
- def move!(new_folder)
138
- new_folder = new_folder.id if new_folder.kind_of?(GenericFolder)
139
- move_opts = {
140
- :to_folder_id => {:id => new_folder},
141
- :item_ids => [{:item_id => {:id => self.id}}]
142
- }
143
- resp = @ews.move_item(move_opts)
144
- rmsg = resp.response_messages[0]
145
-
146
- if rmsg.success?
147
- obj = rmsg.items.first
148
- itype = obj.keys.first
149
- obj[itype][:elems][0][:item_id][:attribs][:id]
150
- else
151
- raise EwsError, "Could not move item. #{resp.code}: #{resp.message}"
152
- end
153
- end
144
+ # Move this item to a new folder
145
+ # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
146
+ # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
147
+ # @return [String] the new Id of the moved item
148
+ def move!(new_folder)
149
+ new_folder = new_folder.id if new_folder.is_a?(GenericFolder)
150
+ move_opts = {
151
+ to_folder_id: { id: new_folder },
152
+ item_ids: [{ item_id: { id: id } }]
153
+ }
154
+ resp = @ews.move_item(move_opts)
155
+ rmsg = resp.response_messages[0]
154
156
 
155
- # Copy this item to a new folder
156
- # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
157
- # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
158
- # @return [String] the new Id of the copied item
159
- def copy(new_folder)
160
- new_folder = new_folder.id if new_folder.kind_of?(GenericFolder)
161
- copy_opts = {
162
- :to_folder_id => {:id => new_folder},
163
- :item_ids => [{:item_id => {:id => self.id}}]
164
- }
165
- resp = @ews.copy_item(copy_opts)
166
- rmsg = resp.response_messages[0]
167
-
168
- if rmsg.success?
169
- obj = rmsg.items.first
170
- itype = obj.keys.first
171
- obj[itype][:elems][0][:item_id][:attribs][:id]
172
- else
173
- raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}"
174
- end
175
- end
157
+ raise EwsError, "Could not move item. #{resp.code}: #{resp.message}" unless rmsg.success?
176
158
 
177
- def add_file_attachment(file)
178
- fa = OpenStruct.new
179
- fa.name = File.basename(file.path)
180
- fa.content = Base64.encode64(file.read)
181
- @new_file_attachments << fa
182
- end
159
+ obj = rmsg.items.first
160
+ itype = obj.keys.first
161
+ obj[itype][:elems][0][:item_id][:attribs][:id]
162
+ end
183
163
 
184
- def add_item_attachment(other_item, name = nil)
185
- ia = OpenStruct.new
186
- ia.name = (name ? name : other_item.subject)
187
- ia.item = {id: other_item.id, change_key: other_item.change_key}
188
- @new_item_attachments << ia
189
- end
164
+ # Copy this item to a new folder
165
+ # @param [String,Symbol,GenericFolder] new_folder The new folder to move it to. This should
166
+ # be a subclass of GenericFolder, a DistinguishedFolderId (must me a Symbol) or a FolderId (String)
167
+ # @return [String] the new Id of the copied item
168
+ def copy(new_folder)
169
+ new_folder = new_folder.id if new_folder.is_a?(GenericFolder)
170
+ copy_opts = {
171
+ to_folder_id: { id: new_folder },
172
+ item_ids: [{ item_id: { id: id } }]
173
+ }
174
+ resp = @ews.copy_item(copy_opts)
175
+ rmsg = resp.response_messages[0]
190
176
 
191
- def add_inline_attachment(file)
192
- fi = OpenStruct.new
193
- fi.name = File.basename(file.path)
194
- fi.content = Base64.encode64(file.read)
195
- @new_inline_attachments << fi
196
- end
177
+ raise EwsError, "Could not copy item. #{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success?
197
178
 
198
- def submit!
199
- if draft?
200
- submit_attachments!
201
- resp = ews.send_item(item_ids: [{item_id: {id: self.id, change_key: self.change_key}}])
202
- rm = resp.response_messages[0]
203
- if rm.success?
204
- true
205
- else
206
- raise EwsSendItemError, "#{rm.code}: #{rm.message_text}"
179
+ obj = rmsg.items.first
180
+ itype = obj.keys.first
181
+ obj[itype][:elems][0][:item_id][:attribs][:id]
207
182
  end
208
- else
209
- false
210
- end
211
- end
212
183
 
213
- def submit_attachments!
214
- return false unless draft? && !(@new_file_attachments.empty? && @new_item_attachments.empty? && @new_inline_attachments.empty?)
215
-
216
- opts = {
217
- parent_id: {id: self.id, change_key: self.change_key},
218
- files: @new_file_attachments,
219
- items: @new_item_attachments,
220
- inline_files: @new_inline_attachments
221
- }
222
- resp = ews.create_attachment(opts)
223
- set_change_key resp.response_messages[0].attachments[0].parent_change_key
224
- @new_file_attachments = []
225
- @new_item_attachments = []
226
- @new_inline_attachments = []
227
- end
184
+ def add_file_attachment(file)
185
+ fa = OpenStruct.new
186
+ fa.name = File.basename(file.path)
187
+ fa.content = Base64.encode64(file.read)
188
+ @new_file_attachments << fa
189
+ end
228
190
 
229
- # If you want to add to the body set #new_body_content. If you set #body
230
- # it will override the body that is there.
231
- # @see MessageAccessors#send_message for options
232
- # additional options:
233
- # :new_body_content, :new_body_type
234
- # @example
235
- # item.forward do |i|
236
- # i.new_body_content = "Add this to the top"
237
- # i.to_recipients << 'test@example.com'
238
- # end
239
- def forward(opts = {})
240
- msg = Template::ForwardItem.new opts.clone
241
- yield msg if block_given?
242
- msg.reference_item_id = {id: self.id, change_key: self.change_key}
243
- dispatch_create_item! msg
244
- end
191
+ def add_item_attachment(other_item, name = nil)
192
+ ia = OpenStruct.new
193
+ ia.name = (name || other_item.subject)
194
+ ia.item = { id: other_item.id, change_key: other_item.change_key }
195
+ @new_item_attachments << ia
196
+ end
245
197
 
246
- def reply_to(opts = {})
247
- msg = Template::ReplyToItem.new opts.clone
248
- yield msg if block_given?
249
- msg.reference_item_id = {id: self.id, change_key: self.change_key}
250
- dispatch_create_item! msg
251
- end
198
+ def add_inline_attachment(file)
199
+ fi = OpenStruct.new
200
+ fi.name = File.basename(file.path)
201
+ fi.content = Base64.encode64(file.read)
202
+ @new_inline_attachments << fi
203
+ end
252
204
 
253
- def reply_to_all(opts = {})
254
- msg = Template::ReplyToItem.new opts.clone
255
- yield msg if block_given?
256
- msg.reference_item_id = {id: self.id, change_key: self.change_key}
257
- msg.ews_type = :reply_all_to_item
258
- dispatch_create_item! msg
259
- end
205
+ def submit!
206
+ if draft?
207
+ submit_attachments!
208
+ resp = ews.send_item(item_ids: [{ item_id: { id: id, change_key: change_key } }])
209
+ rm = resp.response_messages[0]
210
+ rm.success? || raise(EwsSendItemError, "#{rm.code}: #{rm.message_text}")
211
+ else
212
+ false
213
+ end
214
+ end
260
215
 
216
+ def submit_attachments!
217
+ new_attachments = @new_file_attachments + @new_item_attachments + @new_inline_attachments
218
+ return false unless draft? && !new_attachments.empty?
261
219
 
262
- private
220
+ opts = {
221
+ parent_id: { id: id, change_key: change_key },
222
+ files: @new_file_attachments,
223
+ items: @new_item_attachments,
224
+ inline_files: @new_inline_attachments
225
+ }
226
+ resp = ews.create_attachment(opts)
227
+ set_change_key resp.response_messages[0].attachments[0].parent_change_key
228
+ @new_file_attachments = []
229
+ @new_item_attachments = []
230
+ @new_inline_attachments = []
231
+ end
263
232
 
264
- def key_paths
265
- super.merge(ITEM_KEY_PATHS)
266
- end
233
+ # If you want to add to the body set #new_body_content. If you set #body
234
+ # it will override the body that is there.
235
+ # @see MessageAccessors#send_message for options
236
+ # additional options:
237
+ # :new_body_content, :new_body_type
238
+ # @example
239
+ # item.forward do |i|
240
+ # i.new_body_content = "Add this to the top"
241
+ # i.to_recipients << 'test@example.com'
242
+ # end
243
+ def forward(opts = {})
244
+ msg = Template::ForwardItem.new opts.clone
245
+ yield msg if block_given?
246
+ msg.reference_item_id = { id: id, change_key: change_key }
247
+ dispatch_create_item! msg
248
+ end
267
249
 
268
- def key_types
269
- super.merge(ITEM_KEY_TYPES)
270
- end
250
+ def reply_to(opts = {})
251
+ msg = Template::ReplyToItem.new opts.clone
252
+ yield msg if block_given?
253
+ msg.reference_item_id = { id: id, change_key: change_key }
254
+ dispatch_create_item! msg
255
+ end
271
256
 
272
- def key_alias
273
- super.merge(ITEM_KEY_ALIAS)
274
- end
257
+ def reply_to_all(opts = {})
258
+ msg = Template::ReplyToItem.new opts.clone
259
+ yield msg if block_given?
260
+ msg.reference_item_id = { id: id, change_key: change_key }
261
+ msg.ews_type = :reply_all_to_item
262
+ dispatch_create_item! msg
263
+ end
264
+
265
+ private
275
266
 
276
- def update_is_read_status(read)
277
- field = :is_read
278
- opts = {item_changes:
279
- [
280
- { item_id: {id: id, change_key: change_key},
281
- updates: [
282
- {set_item_field: {field_uRI: {field_uRI: FIELD_URIS[field][:text]},
283
- message: {sub_elements: [{field => {text: read}}]}}}
284
- ]
267
+ def key_paths
268
+ super.merge(ITEM_KEY_PATHS)
269
+ end
270
+
271
+ def key_types
272
+ super.merge(ITEM_KEY_TYPES)
273
+ end
274
+
275
+ def key_alias
276
+ super.merge(ITEM_KEY_ALIAS)
277
+ end
278
+
279
+ def update_is_read_status(read)
280
+ field = :is_read
281
+ opts = { item_changes:
282
+ [
283
+ { item_id: { id: id, change_key: change_key },
284
+ updates: [
285
+ { set_item_field: { field_uRI: { field_uRI: FIELD_URIS[field][:text] },
286
+ message: { sub_elements: [{ field => { text: read } }] } } }
287
+ ] }
288
+ ] }
289
+ resp = ews.update_item({ conflict_resolution: 'AutoResolve' }.merge(opts))
290
+ rmsg = resp.response_messages[0]
291
+ raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}" unless rmsg.success?
292
+
293
+ true
294
+ end
295
+
296
+ def simplify!
297
+ return unless @ews_item.key?(:elems)
298
+
299
+ @ews_item = @ews_item[:elems].each_with_object({}) do |i, o|
300
+ key = i.keys.first
301
+ if o.key?(key)
302
+ if o[key].is_a?(Array)
303
+ o[key] << i[key]
304
+ else
305
+ o[key] = [o.delete(key), i[key]]
306
+ end
307
+ else
308
+ o[key] = i[key]
309
+ end
310
+ end
311
+ end
312
+
313
+ # Get a specific item by its ID.
314
+ # @param [Hash] opts Misc options to control request
315
+ # @option opts [String] :base_shape IdOnly/Default/AllProperties
316
+ # @raise [EwsError] raised when the backend SOAP method returns an error.
317
+ def get_item(opts = {})
318
+ args = get_item_args(opts)
319
+ resp = ews.get_item(args)
320
+ get_item_parser(resp)
321
+ end
322
+
323
+ # Build up the arguements for #get_item
324
+ # @todo: should we really pass the ChangeKey or do we want the freshest obj?
325
+ def get_item_args(opts)
326
+ opts[:base_shape] ||= 'Default'
327
+ default_args = {
328
+ item_shape: { base_shape: opts[:base_shape] },
329
+ item_ids: [{ item_id: { id: id, change_key: change_key } }]
285
330
  }
286
- ]
287
- }
288
- resp = ews.update_item({conflict_resolution: 'AutoResolve'}.merge(opts))
289
- rmsg = resp.response_messages[0]
290
- unless rmsg.success?
291
- raise EwsError, "#{rmsg.response_code}: #{rmsg.message_text}"
292
- end
293
- true
294
- end
331
+ default_args[:item_shape][:body_type] = @body_type if @body_type
332
+ default_args
333
+ end
295
334
 
296
- def simplify!
297
- return unless @ews_item.has_key?(:elems)
298
- @ews_item = @ews_item[:elems].inject({}) do |o,i|
299
- key = i.keys.first
300
- if o.has_key?(key)
301
- if o[key].is_a?(Array)
302
- o[key] << i[key]
303
- else
304
- o[key] = [o.delete(key), i[key]]
335
+ def get_item_parser(resp)
336
+ rm = resp.response_messages[0]
337
+ unless rm.status == 'Success'
338
+ raise EwsError,
339
+ "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}"
305
340
  end
306
- else
307
- o[key] = i[key]
341
+
342
+ rm.items[0].values.first
308
343
  end
309
- o
310
- end
311
- end
312
344
 
313
- # Get a specific item by its ID.
314
- # @param [Hash] opts Misc options to control request
315
- # @option opts [String] :base_shape IdOnly/Default/AllProperties
316
- # @raise [EwsError] raised when the backend SOAP method returns an error.
317
- def get_item(opts = {})
318
- args = get_item_args(opts)
319
- resp = ews.get_item(args)
320
- get_item_parser(resp)
321
- end
345
+ # Map a delete type to what EWS expects
346
+ # @param [Symbol] type. Must be :hard, :soft, or :recycle
347
+ def delete_type(type)
348
+ case type
349
+ when :hard then 'HardDelete'
350
+ when :soft then 'SoftDelete'
351
+ when :recycle then 'MoveToDeletedItems'
352
+ else 'MoveToDeletedItems'
353
+ end
354
+ end
322
355
 
323
- # Build up the arguements for #get_item
324
- # @todo: should we really pass the ChangeKey or do we want the freshest obj?
325
- def get_item_args(opts)
326
- opts[:base_shape] ||= 'Default'
327
- default_args = {
328
- item_shape: {base_shape: opts[:base_shape]},
329
- item_ids: [{item_id:{id: id, change_key: change_key}}]
330
- }
331
- default_args[:item_shape][:body_type] = @body_type if @body_type
332
- default_args
333
- end
356
+ def build_deleted_occurrences(occurrences)
357
+ occurrences.collect { |a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text] }
358
+ end
334
359
 
335
- def get_item_parser(resp)
336
- rm = resp.response_messages[0]
337
- if(rm.status == 'Success')
338
- rm.items[0].values.first
339
- else
340
- raise EwsError, "Could not retrieve #{self.class}. #{rm.code}: #{rm.message_text}"
341
- end
342
- end
360
+ def build_modified_occurrences(occurrences)
361
+ {}.tap do |h|
362
+ occurrences.collect do |a|
363
+ elems = a[:occurrence][:elems]
343
364
 
344
- # Map a delete type to what EWS expects
345
- # @param [Symbol] type. Must be :hard, :soft, or :recycle
346
- def delete_type(type)
347
- case type
348
- when :hard then 'HardDelete'
349
- when :soft then 'SoftDelete'
350
- when :recycle then 'MoveToDeletedItems'
351
- else 'MoveToDeletedItems'
352
- end
353
- end
365
+ h[DateTime.parse(elems.find { |e| e[:original_start] }[:original_start][:text])] = {
366
+ start: elems.find { |e| e[:start] }[:start][:text],
367
+ end: elems.find { |e| e[:end] }[:end][:text]
368
+ }
369
+ end
370
+ end
371
+ end
354
372
 
355
- def build_deleted_occurrences(occurrences)
356
- occurrences.collect{|a| DateTime.parse a[:deleted_occurrence][:elems][0][:start][:text]}
357
- end
373
+ def build_mailbox_user(mbox_ews)
374
+ MailboxUser.new(ews, mbox_ews)
375
+ end
358
376
 
359
- def build_modified_occurrences(occurrences)
360
- {}.tap do |h|
361
- occurrences.collect do |a|
362
- elems = a[:occurrence][:elems]
377
+ def build_mailbox_users(users)
378
+ return [] if users.nil?
363
379
 
364
- h[DateTime.parse(elems.find{|e| e[:original_start]}[:original_start][:text])] = {
365
- start: elems.find{|e| e[:start]}[:start][:text],
366
- end: elems.find{|e| e[:end]}[:end][:text]
367
- }
380
+ users.collect { |u| build_mailbox_user(u[:mailbox][:elems]) }
368
381
  end
369
- end
370
- end
371
382
 
372
- def build_mailbox_user(mbox_ews)
373
- MailboxUser.new(ews, mbox_ews)
374
- end
383
+ def build_attendees_users(users)
384
+ return [] if users.nil?
375
385
 
376
- def build_mailbox_users(users)
377
- return [] if users.nil?
378
- users.collect{|u| build_mailbox_user(u[:mailbox][:elems])}
379
- end
386
+ users.collect { |u|
387
+ u[:attendee][:elems].collect do |a|
388
+ build_mailbox_user(a[:mailbox][:elems]) if a[:mailbox]
389
+ end
390
+ }.flatten.compact
391
+ end
380
392
 
381
- def build_attendees_users(users)
382
- return [] if users.nil?
383
- users.collect do |u|
384
- u[:attendee][:elems].collect do |a|
385
- build_mailbox_user(a[:mailbox][:elems]) if a[:mailbox]
393
+ def build_attachments(attachments)
394
+ return [] if attachments.nil?
395
+
396
+ attachments.collect do |att|
397
+ key = att.keys.first
398
+ class_by_name(key).new(self, att[key])
399
+ end
386
400
  end
387
- end.flatten.compact
388
- end
389
401
 
390
- def build_attachments(attachments)
391
- return [] if attachments.nil?
392
- attachments.collect do |att|
393
- key = att.keys.first
394
- class_by_name(key).new(self, att[key])
395
- end
396
- end
402
+ def set_change_key(change_key) # rubocop:disable Naming/AccessorMethodName -- public API name
403
+ p = resolve_key_path(ews_item, key_paths[:change_key][0..-2])
404
+ p[:change_key] = change_key
405
+ end
397
406
 
398
- def set_change_key(ck)
399
- p = resolve_key_path(ews_item, key_paths[:change_key][0..-2])
400
- p[:change_key] = ck
401
- end
407
+ # Handles the CreateItem call for Forward, ReplyTo, and ReplyAllTo
408
+ # It will handle the neccessary actions for adding attachments.
409
+ def dispatch_create_item!(msg)
410
+ if msg.has_attachments?
411
+ draft = msg.draft
412
+ msg.draft = true
413
+ resp = validate_created_item(ews.create_item(msg.to_ews))
414
+ msg.file_attachments.each do |f|
415
+ next unless f.is_a?(File)
416
+
417
+ resp.add_file_attachment(f)
418
+ end
419
+ if draft
420
+ resp.submit_attachments!
421
+ resp
422
+ else
423
+ resp.submit!
424
+ end
425
+ else
426
+ resp = ews.create_item(msg.to_ews)
427
+ validate_created_item resp
428
+ end
429
+ end
402
430
 
403
- # Handles the CreateItem call for Forward, ReplyTo, and ReplyAllTo
404
- # It will handle the neccessary actions for adding attachments.
405
- def dispatch_create_item!(msg)
406
- if msg.has_attachments?
407
- draft = msg.draft
408
- msg.draft = true
409
- resp = validate_created_item(ews.create_item(msg.to_ews))
410
- msg.file_attachments.each do |f|
411
- next unless f.kind_of?(File)
412
- resp.add_file_attachment(f)
413
- end
414
- if draft
415
- resp.submit_attachments!
416
- resp
417
- else
418
- resp.submit!
419
- end
420
- else
421
- resp = ews.create_item(msg.to_ews)
422
- validate_created_item resp
423
- end
424
- end
431
+ # validate the CreateItem response.
432
+ # @return [Boolean, Item] returns true if items is empty and status is
433
+ # "Success" if items is not empty it will return the first Item since
434
+ # we are only dealing with single items here.
435
+ # @raise EwsCreateItemError on failure
436
+ def validate_created_item(response)
437
+ msg = response.response_messages[0]
425
438
 
426
- # validate the CreateItem response.
427
- # @return [Boolean, Item] returns true if items is empty and status is
428
- # "Success" if items is not empty it will return the first Item since
429
- # we are only dealing with single items here.
430
- # @raise EwsCreateItemError on failure
431
- def validate_created_item(response)
432
- msg = response.response_messages[0]
433
-
434
- if(msg.status == 'Success')
435
- msg.items.empty? ? true : parse_created_item(msg.items.first)
436
- else
437
- raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}"
438
- end
439
- end
439
+ raise EwsCreateItemError, "#{msg.code}: #{msg.message_text}" unless msg.status == 'Success'
440
440
 
441
- def parse_created_item(msg)
442
- mtype = msg.keys.first
443
- message = class_by_name(mtype).new(ews, msg[mtype])
444
- end
441
+ msg.items.empty? || parse_created_item(msg.items.first)
442
+ end
445
443
 
444
+ def parse_created_item(msg)
445
+ mtype = msg.keys.first
446
+ class_by_name(mtype).new(ews, msg[mtype])
447
+ end
448
+ end
449
+ end
446
450
  end
447
451
  end