viewpoint 1.2.0 → 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.
- checksums.yaml +4 -4
- data/README.md +11 -6
- data/lib/ews/calendar_accessors.rb +37 -33
- data/lib/ews/connection.rb +152 -125
- data/lib/ews/connection_helper.rb +36 -33
- data/lib/ews/convert_accessors.rb +58 -54
- data/lib/ews/errors.rb +59 -53
- data/lib/ews/ews_client.rb +92 -79
- data/lib/ews/exceptions/exceptions.rb +61 -61
- data/lib/ews/folder_accessors.rb +235 -234
- data/lib/ews/impersonation.rb +29 -23
- data/lib/ews/item_accessors.rb +215 -213
- data/lib/ews/mailbox_accessors.rb +82 -79
- data/lib/ews/meeting_accessors.rb +38 -31
- data/lib/ews/message_accessors.rb +83 -81
- data/lib/ews/push_subscription_accessors.rb +29 -27
- data/lib/ews/room_accessors.rb +48 -46
- data/lib/ews/roomlist_accessors.rb +47 -45
- data/lib/ews/soap/builders/ews_builder.rb +1191 -1176
- data/lib/ews/soap/ews_response.rb +68 -73
- data/lib/ews/soap/ews_soap_availability_response.rb +57 -57
- data/lib/ews/soap/ews_soap_free_busy_response.rb +115 -117
- data/lib/ews/soap/ews_soap_response.rb +99 -101
- data/lib/ews/soap/ews_soap_room_response.rb +45 -45
- data/lib/ews/soap/ews_soap_roomlist_response.rb +45 -46
- data/lib/ews/soap/exchange_availability.rb +54 -52
- data/lib/ews/soap/exchange_data_services.rb +693 -711
- data/lib/ews/soap/exchange_notification.rb +123 -128
- data/lib/ews/soap/exchange_synchronization.rb +82 -82
- data/lib/ews/soap/exchange_time_zones.rb +41 -44
- data/lib/ews/soap/exchange_user_configuration.rb +30 -27
- data/lib/ews/soap/exchange_web_service.rb +237 -233
- data/lib/ews/soap/parsers/ews_parser.rb +46 -42
- data/lib/ews/soap/parsers/ews_sax_document.rb +63 -58
- data/lib/ews/soap/response_message.rb +69 -68
- data/lib/ews/soap/responses/create_attachment_response_message.rb +45 -45
- data/lib/ews/soap/responses/create_item_response_message.rb +26 -25
- data/lib/ews/soap/responses/find_item_response_message.rb +76 -78
- data/lib/ews/soap/responses/get_events_response_message.rb +52 -51
- data/lib/ews/soap/responses/send_notification_response_message.rb +53 -51
- data/lib/ews/soap/responses/subscribe_response_message.rb +37 -34
- data/lib/ews/soap/responses/sync_folder_hierarchy_response_message.rb +38 -35
- data/lib/ews/soap/responses/sync_folder_items_response_message.rb +38 -35
- data/lib/ews/soap.rb +27 -26
- data/lib/ews/templates/calendar_item.rb +64 -60
- data/lib/ews/templates/forward_item.rb +19 -17
- data/lib/ews/templates/message.rb +61 -58
- data/lib/ews/templates/reply_to_item.rb +20 -18
- data/lib/ews/templates/task.rb +55 -55
- data/lib/ews/types/attachment.rb +75 -74
- data/lib/ews/types/attendee.rb +27 -25
- data/lib/ews/types/calendar_folder.rb +58 -59
- data/lib/ews/types/calendar_item.rb +133 -131
- data/lib/ews/types/contact.rb +11 -5
- data/lib/ews/types/contacts_folder.rb +10 -5
- data/lib/ews/types/copied_event.rb +47 -48
- data/lib/ews/types/created_event.rb +22 -20
- data/lib/ews/types/deleted_event.rb +22 -20
- data/lib/ews/types/distribution_list.rb +11 -5
- data/lib/ews/types/event.rb +60 -59
- data/lib/ews/types/export_items_response_message.rb +54 -50
- data/lib/ews/types/file_attachment.rb +63 -61
- data/lib/ews/types/folder.rb +58 -57
- data/lib/ews/types/free_busy_changed_event.rb +22 -20
- data/lib/ews/types/generic_folder.rb +348 -372
- data/lib/ews/types/item.rb +401 -397
- data/lib/ews/types/item_attachment.rb +87 -80
- data/lib/ews/types/item_field_uri_map.rb +201 -200
- data/lib/ews/types/mailbox_user.rb +146 -154
- data/lib/ews/types/meeting_cancellation.rb +11 -5
- data/lib/ews/types/meeting_message.rb +11 -5
- data/lib/ews/types/meeting_request.rb +11 -5
- data/lib/ews/types/meeting_response.rb +11 -5
- data/lib/ews/types/message.rb +11 -5
- data/lib/ews/types/modified_event.rb +43 -45
- data/lib/ews/types/moved_event.rb +47 -48
- data/lib/ews/types/new_mail_event.rb +22 -20
- data/lib/ews/types/out_of_office.rb +145 -144
- data/lib/ews/types/post_item.rb +11 -5
- data/lib/ews/types/search_folder.rb +10 -5
- data/lib/ews/types/status_event.rb +37 -36
- data/lib/ews/types/task.rb +39 -33
- data/lib/ews/types/tasks_folder.rb +31 -25
- data/lib/ews/types.rb +134 -139
- data/lib/viewpoint/logging/config.rb +19 -19
- data/lib/viewpoint/logging.rb +23 -17
- data/lib/viewpoint/string_utils.rb +31 -32
- data/lib/viewpoint.rb +18 -18
- metadata +50 -25
- data/Changelog.txt +0 -1004
data/lib/ews/types/item.rb
CHANGED
|
@@ -1,447 +1,451 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
107
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
def recycle!
|
|
126
|
+
delete! :recycle
|
|
127
|
+
end
|
|
117
128
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
def get_all_properties!
|
|
130
|
+
@ews_item = get_item(base_shape: 'AllProperties')
|
|
131
|
+
simplify!
|
|
132
|
+
end
|
|
122
133
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
134
|
+
# Mark an item as read
|
|
135
|
+
def mark_read!
|
|
136
|
+
update_is_read_status true
|
|
137
|
+
end
|
|
127
138
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
# Mark an item as unread
|
|
140
|
+
def mark_unread!
|
|
141
|
+
update_is_read_status false
|
|
142
|
+
end
|
|
132
143
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
307
|
-
|
|
341
|
+
|
|
342
|
+
rm.items[0].values.first
|
|
308
343
|
end
|
|
309
|
-
o
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
344
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
373
|
+
def build_mailbox_user(mbox_ews)
|
|
374
|
+
MailboxUser.new(ews, mbox_ews)
|
|
375
|
+
end
|
|
358
376
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
occurrences.collect do |a|
|
|
362
|
-
elems = a[:occurrence][:elems]
|
|
377
|
+
def build_mailbox_users(users)
|
|
378
|
+
return [] if users.nil?
|
|
363
379
|
|
|
364
|
-
|
|
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
|
-
|
|
373
|
-
|
|
374
|
-
end
|
|
383
|
+
def build_attendees_users(users)
|
|
384
|
+
return [] if users.nil?
|
|
375
385
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
-
|
|
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
|
-
|
|
442
|
-
|
|
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
|