rews 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -0
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/lib/rews/client.rb +48 -0
- data/lib/rews/folder.rb +84 -38
- data/lib/rews/item.rb +39 -19
- data/lib/rews/restriction.rb +11 -6
- data/lib/rews/shape.rb +9 -0
- data/lib/rews/sort_order.rb +7 -3
- data/lib/rews/util.rb +14 -7
- data/lib/rews/view.rb +8 -0
- data/lib/rews.rb +1 -33
- data/spec/request_proxy.rb +18 -0
- data/spec/rews/client_spec.rb +21 -0
- data/spec/rews/folder_spec.rb +402 -0
- data/spec/rews/item_spec.rb +124 -0
- data/spec/rews/restriction_spec.rb +53 -0
- data/spec/rews/shape_spec.rb +36 -0
- data/spec/rews/sort_order_spec.rb +56 -0
- data/spec/rews/util_spec.rb +103 -0
- data/spec/rews/view_spec.rb +35 -0
- data/spec/spec_helper.rb +2 -0
- metadata +43 -9
- data/spec/rews_spec.rb +0 -4
data/README.rdoc
CHANGED
@@ -35,6 +35,12 @@ to use :
|
|
35
35
|
|
36
36
|
== Install
|
37
37
|
|
38
|
+
to use NTLM authentication, you need versions of httpclient and ntlm-http
|
39
|
+
gems with fixes for NTLM authentication
|
40
|
+
|
41
|
+
* httpclient branch ntlm_domain : https://github.com/mccraigmccraig/httpclient/tree/ntlm_domain
|
42
|
+
* ntlm-http branch fix_unicode : https://github.com/trampoline/ntlm-http/tree/fix_unicode
|
43
|
+
|
38
44
|
gem install rews
|
39
45
|
|
40
46
|
== Note on Patches/Pull Requests
|
data/Rakefile
CHANGED
@@ -11,11 +11,12 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/trampoline/rews"
|
12
12
|
gem.authors = ["Trampoline Systems Ltd"]
|
13
13
|
gem.add_dependency "savon", ">= 0.8.6"
|
14
|
-
gem.add_dependency "ntlm-http", ">= 0.1.1"
|
14
|
+
gem.add_dependency "ntlm-http", ">= 0.1.1.1"
|
15
15
|
gem.add_dependency "httpclient", ">= 2.1.6.1.1"
|
16
16
|
gem.add_dependency "fetch_in", ">= 0.2.0"
|
17
17
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
18
18
|
gem.add_development_dependency "rr", ">= 0.10.5"
|
19
|
+
gem.add_development_dependency "nokogiri", ">= 1.4.4"
|
19
20
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
20
21
|
end
|
21
22
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/rews/client.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Rews
|
2
|
+
class Client
|
3
|
+
attr_reader :client
|
4
|
+
attr_accessor :logdev
|
5
|
+
|
6
|
+
# create a +Client+ to access Exchange Web Services
|
7
|
+
# * using NTLM authentication
|
8
|
+
# Rews::Client.new('https://exchange.foo.com/EWS/Exchange.asmx', :ntlm, 'DOMAIN\\user', 'password')
|
9
|
+
# * using basic authentication
|
10
|
+
# Rews::Client.new('https://exchange.foo.com/EWS/Exchange.asmx', :basic, 'DOMAIN\\user', 'password')
|
11
|
+
def initialize(endpoint, auth_type, user, password)
|
12
|
+
@endpoint=endpoint
|
13
|
+
@auth_type = auth_type
|
14
|
+
@user=user
|
15
|
+
@password=password
|
16
|
+
@client = Savon::Client.new do
|
17
|
+
wsdl.endpoint = endpoint
|
18
|
+
wsdl.namespace = SCHEMA_MESSAGES
|
19
|
+
|
20
|
+
http.auth.ssl.verify_mode = :none
|
21
|
+
http.auth.send(auth_type, user, password)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class} @endpoint=#{@endpoint}, @auth_type=#{@auth_type}, @user=#{@user}, @password=#{@password}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
# get a <tt>Folder::DistinguishedFolderId</tt> referencing one of the named top-level Folders in an Exchange mailbox
|
30
|
+
# * get a folder from the default mailbox
|
31
|
+
# client.distinguished_folder_id('inbox')
|
32
|
+
# * get a folder from another mailbox
|
33
|
+
# client.distinguished_folder_id('inbox', 'foo@bar.com')
|
34
|
+
def distinguished_folder_id(id, mailbox_email=nil)
|
35
|
+
Folder::DistinguishedFolderId.new(client, id, mailbox_email)
|
36
|
+
end
|
37
|
+
|
38
|
+
# yield a +Logger+ if +logdev+ has been set
|
39
|
+
def log
|
40
|
+
yield logger if @logdev
|
41
|
+
end
|
42
|
+
|
43
|
+
def logger
|
44
|
+
return @logger if @logger
|
45
|
+
@logger = Logger.new(@logdev) if @logdev
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/rews/folder.rb
CHANGED
@@ -1,24 +1,41 @@
|
|
1
1
|
module Rews
|
2
2
|
module Folder
|
3
|
+
|
4
|
+
# represents a Folder in a mailbox on an Exchange server
|
3
5
|
class Folder
|
4
6
|
attr_reader :client
|
5
7
|
attr_reader :folder_id
|
6
8
|
attr_reader :attributes
|
7
9
|
|
8
10
|
def initialize(client, folder)
|
11
|
+
@client = client
|
9
12
|
@folder_id = VanillaFolderId.new(client, folder[:folder_id])
|
10
13
|
@attributes = folder
|
11
14
|
end
|
12
15
|
|
16
|
+
def ==(other)
|
17
|
+
other.is_a?(Folder) &&
|
18
|
+
@client == other.client &&
|
19
|
+
@folder_id == other.folder_id &&
|
20
|
+
@attributes == other.attributes
|
21
|
+
end
|
22
|
+
|
23
|
+
# access the +Folder+ +attributes+
|
13
24
|
def [](key)
|
14
25
|
@attributes[key]
|
15
26
|
end
|
16
27
|
|
28
|
+
# keys of the +Folder+ +attributes+
|
17
29
|
def keys
|
18
30
|
@attributes.keys
|
19
31
|
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<#{self.class} @folder_id=#{@folder_id.inspect}, @attributes=#{@attributes.inspect}>"
|
35
|
+
end
|
20
36
|
end
|
21
37
|
|
38
|
+
# <tt>find_*</tt> methods on <tt>Folder::BaseFolderId</tt> return a +FindResult+
|
22
39
|
class FindResult
|
23
40
|
VIEW_ATTRS = [:includes_last_item_in_range,
|
24
41
|
:indexed_paging_offset,
|
@@ -27,6 +44,8 @@ module Rews
|
|
27
44
|
VIEW_ATTRS.each do |attr|
|
28
45
|
attr_reader attr
|
29
46
|
end
|
47
|
+
|
48
|
+
# the +result+ of the +find_*+ call
|
30
49
|
attr_reader :result
|
31
50
|
|
32
51
|
def initialize(view, &proc)
|
@@ -36,19 +55,28 @@ module Rews
|
|
36
55
|
@result = proc.call(view) if proc
|
37
56
|
end
|
38
57
|
|
58
|
+
# count of items in the +result+
|
39
59
|
def length
|
40
60
|
result.length
|
41
61
|
end
|
42
62
|
|
63
|
+
# alias for +length+
|
43
64
|
def size
|
44
65
|
result.size
|
45
66
|
end
|
46
67
|
|
68
|
+
# access an element from +result+
|
47
69
|
def [](key)
|
48
70
|
result[key]
|
49
71
|
end
|
72
|
+
|
73
|
+
def inspect
|
74
|
+
attrs = VIEW_ATTRS.map{|attr| "@#{attr}=#{self.send(attr)}"}.join(", ")
|
75
|
+
"#<#{self.class} #{attrs}, @result=#{@result.inspect}>"
|
76
|
+
end
|
50
77
|
end
|
51
78
|
|
79
|
+
# Identifies a Folder
|
52
80
|
class BaseFolderId
|
53
81
|
include Util
|
54
82
|
|
@@ -63,6 +91,7 @@ module Rews
|
|
63
91
|
:indexed_page_folder_view=>View::INDEXED_PAGE_VIEW_OPTS,
|
64
92
|
:folder_shape=>Shape::FOLDER_SHAPE_OPTS}
|
65
93
|
|
94
|
+
# find <tt>Folder::Folder</tt>s within a <tt>Folder::Folder</tt>
|
66
95
|
def find_folder(opts={})
|
67
96
|
opts = check_opts(FIND_FOLDER_OPTS, opts)
|
68
97
|
|
@@ -76,7 +105,7 @@ module Rews
|
|
76
105
|
xml << Restriction.new(opts[:restriction]).to_xml if opts[:restriction]
|
77
106
|
|
78
107
|
xml.wsdl :ParentFolderIds do
|
79
|
-
xml <<
|
108
|
+
xml << self.to_xml
|
80
109
|
end
|
81
110
|
soap.body = xml.target!
|
82
111
|
end
|
@@ -91,6 +120,7 @@ module Rews
|
|
91
120
|
end
|
92
121
|
end
|
93
122
|
|
123
|
+
# find <tt>Folder::FolderIds</tt>s within a <tt>Folder::FolderIds</tt>
|
94
124
|
def find_folder_id(opts={})
|
95
125
|
opts = check_opts(FIND_FOLDER_OPTS, opts)
|
96
126
|
|
@@ -108,7 +138,7 @@ module Rews
|
|
108
138
|
:indexed_page_item_view=>View::INDEXED_PAGE_VIEW_OPTS,
|
109
139
|
:item_shape=>Shape::ITEM_SHAPE_OPTS}
|
110
140
|
|
111
|
-
# find
|
141
|
+
# find <tt>Item::Item</tt>s in a folder
|
112
142
|
def find_item(opts={})
|
113
143
|
opts = check_opts(FIND_ITEM_OPTS, opts)
|
114
144
|
|
@@ -124,7 +154,7 @@ module Rews
|
|
124
154
|
xml << SortOrder.new(opts[:sort_order]).to_xml if opts[:sort_order]
|
125
155
|
|
126
156
|
xml.wsdl :ParentFolderIds do
|
127
|
-
xml <<
|
157
|
+
xml << self.to_xml
|
128
158
|
end
|
129
159
|
|
130
160
|
soap.body = xml.target!
|
@@ -136,6 +166,7 @@ module Rews
|
|
136
166
|
end
|
137
167
|
end
|
138
168
|
|
169
|
+
# find <tt>Item::ItemIds</tt>s in a folder
|
139
170
|
def find_item_id(opts={})
|
140
171
|
opts = check_opts(FIND_ITEM_OPTS, opts)
|
141
172
|
|
@@ -152,7 +183,9 @@ module Rews
|
|
152
183
|
:ignore_change_keys=>nil
|
153
184
|
}
|
154
185
|
|
155
|
-
#
|
186
|
+
# retrieve a bunch of <tt>Item::Item</tt>s in one API hit.
|
187
|
+
# takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
|
188
|
+
# or a <tt>Folder::FindResult</tt> and options to specify +Shape::ItemShape+
|
156
189
|
def get_item(message_ids, opts={})
|
157
190
|
opts = check_opts(GET_ITEM_OPTS, opts)
|
158
191
|
message_ids = message_ids.result if message_ids.is_a?(FindResult)
|
@@ -166,7 +199,8 @@ module Rews
|
|
166
199
|
xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
|
167
200
|
xml.wsdl :ItemIds do
|
168
201
|
message_ids.each do |mid|
|
169
|
-
|
202
|
+
mid = mid.item_id if mid.is_a?(Item::Item)
|
203
|
+
xml << mid.to_xml(opts[:ignore_change_keys])
|
170
204
|
end
|
171
205
|
end
|
172
206
|
|
@@ -181,6 +215,9 @@ module Rews
|
|
181
215
|
:ignore_change_keys=>false
|
182
216
|
}
|
183
217
|
|
218
|
+
# delete a bunch of Items in one API hit.
|
219
|
+
# takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
|
220
|
+
# or a <tt>Folder::FindResult</tt> and options to specify DeleteType
|
184
221
|
def delete_item(message_ids, opts={})
|
185
222
|
opts = check_opts(DELETE_ITEM_OPTS, opts)
|
186
223
|
message_ids = message_ids.result if message_ids.is_a?(FindResult)
|
@@ -193,7 +230,8 @@ module Rews
|
|
193
230
|
|
194
231
|
xml.wsdl :ItemIds do
|
195
232
|
message_ids.each do |mid|
|
196
|
-
|
233
|
+
mid = mid.item_id if mid.is_a?(Item::Item)
|
234
|
+
xml << mid.to_xml(opts[:ignore_change_keys])
|
197
235
|
end
|
198
236
|
end
|
199
237
|
|
@@ -204,8 +242,12 @@ module Rews
|
|
204
242
|
end
|
205
243
|
end
|
206
244
|
|
245
|
+
# identifies a regular (non-distinguished) Folder on an Exchange server
|
207
246
|
class VanillaFolderId < BaseFolderId
|
247
|
+
# the Id of the Folder
|
208
248
|
attr_reader :id
|
249
|
+
|
250
|
+
# +change_key+ identifies a specific version of the Folder
|
209
251
|
attr_reader :change_key
|
210
252
|
|
211
253
|
def initialize(client, folder_id)
|
@@ -215,30 +257,33 @@ module Rews
|
|
215
257
|
raise "no id" if !@id
|
216
258
|
end
|
217
259
|
|
218
|
-
def
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
"Id" => id.to_s}}}
|
232
|
-
end
|
260
|
+
def ==(other)
|
261
|
+
other.is_a?(VanillaFolderId) &&
|
262
|
+
@client == other.client &&
|
263
|
+
@id == other.id &&
|
264
|
+
@change_key == other.change_key
|
265
|
+
end
|
266
|
+
|
267
|
+
def to_xml
|
268
|
+
xml = Builder::XmlMarkup.new
|
269
|
+
attrs = {:Id=>id.to_s}
|
270
|
+
attrs[:ChangeKey] = change_key.to_s if change_key
|
271
|
+
xml.t :FolderId, attrs
|
272
|
+
xml.target!
|
233
273
|
end
|
234
274
|
|
235
275
|
def inspect
|
236
|
-
"
|
276
|
+
"#<#{self.class} @id=#{id}, @change_key=#{change_key}>"
|
237
277
|
end
|
238
278
|
end
|
239
279
|
|
280
|
+
# identifies a DistinguishedFolder in a mailbox on an Exchange server.
|
281
|
+
# the <tt>Client.distinguished_folder_id</tt> method returns <tt>DistinguishedFolderId</tt>s
|
240
282
|
class DistinguishedFolderId < BaseFolderId
|
283
|
+
# the Id of the DistinguishedFolder e.g. <tt>"inbox"</tt>
|
241
284
|
attr_reader :id
|
285
|
+
|
286
|
+
# the email address of the mailbox containing the DistinguishedFolder
|
242
287
|
attr_reader :mailbox_email
|
243
288
|
|
244
289
|
def initialize(client, id, mailbox_email=nil)
|
@@ -248,26 +293,27 @@ module Rews
|
|
248
293
|
raise "no id" if !@id
|
249
294
|
end
|
250
295
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
|
296
|
+
def ==(other)
|
297
|
+
other.is_a?(DistinguishedFolderId) &&
|
298
|
+
@client = other.client &&
|
299
|
+
@id = other.id &&
|
300
|
+
@mailbox_email = other.mailbox_email
|
255
301
|
end
|
256
302
|
|
257
|
-
def
|
258
|
-
|
303
|
+
def to_xml
|
304
|
+
xml = Builder::XmlMarkup.new
|
305
|
+
xml.t :DistinguishedFolderId, :Id=>id do
|
306
|
+
if mailbox_email
|
307
|
+
xml.t :Mailbox do
|
308
|
+
xml.t :EmailAddress, mailbox_email
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
xml.target!
|
259
313
|
end
|
260
314
|
|
261
|
-
|
262
|
-
|
263
|
-
def mailbox_xml_hash
|
264
|
-
if mailbox_email
|
265
|
-
{
|
266
|
-
"t:Mailbox"=>{
|
267
|
-
"t:EmailAddress"=>mailbox_email}}
|
268
|
-
else
|
269
|
-
""
|
270
|
-
end
|
315
|
+
def inspect
|
316
|
+
"#<#{self.class} @id=#{id}, @mailbox_email=#{mailbox_email}>"
|
271
317
|
end
|
272
318
|
end
|
273
319
|
end
|
data/lib/rews/item.rb
CHANGED
@@ -20,6 +20,7 @@ module Rews
|
|
20
20
|
end.flatten
|
21
21
|
end
|
22
22
|
|
23
|
+
# represents an Item from a mailbox on an Exchange server
|
23
24
|
class Item
|
24
25
|
attr_reader :client
|
25
26
|
attr_reader :item_id
|
@@ -27,25 +28,45 @@ module Rews
|
|
27
28
|
attr_reader :attributes
|
28
29
|
|
29
30
|
def initialize(client, item_class, attributes)
|
31
|
+
@client = client
|
30
32
|
@item_id = ItemId.new(client, attributes[:item_id])
|
31
33
|
@item_class = item_class
|
32
34
|
@attributes = attributes
|
33
35
|
end
|
34
36
|
|
37
|
+
def ==(other)
|
38
|
+
other.is_a?(Item) &&
|
39
|
+
@client == other.client &&
|
40
|
+
@item_id == other.item_id &&
|
41
|
+
@item_class == other.item_class &&
|
42
|
+
@attributes == other.attributes
|
43
|
+
end
|
44
|
+
|
45
|
+
# access the Item attributes
|
35
46
|
def [](key)
|
36
47
|
@attributes[key]
|
37
48
|
end
|
38
|
-
|
49
|
+
|
50
|
+
# names of the Item attributes
|
39
51
|
def keys
|
40
52
|
@attributes.keys
|
41
53
|
end
|
54
|
+
|
55
|
+
def inspect
|
56
|
+
"#<#{self.class} @item_class=#{@item_class}, @item_id=#{@folder_id.inspect}, @attributes=#{@attributes.inspect}>"
|
57
|
+
end
|
42
58
|
end
|
43
59
|
|
60
|
+
# identifies an Item
|
44
61
|
class ItemId
|
45
62
|
include Util
|
46
63
|
|
47
64
|
attr_reader :client
|
65
|
+
|
66
|
+
# the +Id+ of the Item
|
48
67
|
attr_reader :id
|
68
|
+
|
69
|
+
# the version of the Item
|
49
70
|
attr_reader :change_key
|
50
71
|
|
51
72
|
def initialize(client, item_id)
|
@@ -55,11 +76,18 @@ module Rews
|
|
55
76
|
raise "no id" if !@id
|
56
77
|
end
|
57
78
|
|
79
|
+
def ==(other)
|
80
|
+
@client == other.client &&
|
81
|
+
@id == other.id &&
|
82
|
+
@change_key == other.change_key
|
83
|
+
end
|
84
|
+
|
58
85
|
GET_ITEM_OPTS = {
|
59
86
|
:item_shape=>Shape::ITEM_SHAPE_OPTS,
|
60
87
|
:ignore_change_keys=>nil
|
61
88
|
}
|
62
89
|
|
90
|
+
# get the <tt>Item::Item</tt> identified by this <tt>Item::ItemId</tt>
|
63
91
|
def get_item(opts={})
|
64
92
|
opts = check_opts(GET_ITEM_OPTS, opts)
|
65
93
|
r = with_error_check(client, :get_item_response,:response_messages,:get_item_response_message) do
|
@@ -70,7 +98,7 @@ module Rews
|
|
70
98
|
|
71
99
|
xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
|
72
100
|
xml.wsdl :ItemIds do
|
73
|
-
xml <<
|
101
|
+
xml << self.to_xml(opts[:ignore_change_keys])
|
74
102
|
end
|
75
103
|
|
76
104
|
soap.body = xml.target!
|
@@ -84,6 +112,7 @@ module Rews
|
|
84
112
|
:ignore_change_keys=>false
|
85
113
|
}
|
86
114
|
|
115
|
+
# delete the Item from the server
|
87
116
|
def delete_item(opts={})
|
88
117
|
opts = check_opts(DELETE_ITEM_OPTS, opts)
|
89
118
|
r = with_error_check(client, :delete_item_response, :response_messages, :delete_item_response_message) do
|
@@ -93,7 +122,7 @@ module Rews
|
|
93
122
|
xml = Builder::XmlMarkup.new
|
94
123
|
|
95
124
|
xml.wsdl :ItemIds do
|
96
|
-
xml <<
|
125
|
+
xml << self.to_xml(opts[:ignore_change_keys])
|
97
126
|
end
|
98
127
|
|
99
128
|
soap.body = xml.target!
|
@@ -102,25 +131,16 @@ module Rews
|
|
102
131
|
true
|
103
132
|
end
|
104
133
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
"Id" => id.to_s,
|
112
|
-
"ChangeKey" => change_key.to_s}}}
|
113
|
-
else
|
114
|
-
{
|
115
|
-
"t:ItemId"=>"",
|
116
|
-
:attributes! => {
|
117
|
-
"t:ItemId" => {
|
118
|
-
"Id" => id.to_s}}}
|
119
|
-
end
|
134
|
+
def to_xml(ignore_change_key=false)
|
135
|
+
xml = Builder::XmlMarkup.new
|
136
|
+
attrs = {:Id=>id.to_s}
|
137
|
+
attrs[:ChangeKey] = change_key.to_s if change_key && !ignore_change_key
|
138
|
+
xml.t :ItemId, attrs
|
139
|
+
xml.target!
|
120
140
|
end
|
121
141
|
|
122
142
|
def inspect
|
123
|
-
"
|
143
|
+
"#<#{self.class} @id=#{id}, @change_key=#{change_key}>"
|
124
144
|
end
|
125
145
|
end
|
126
146
|
end
|
data/lib/rews/restriction.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
# takes restrictions written in Ruby s-expressions and
|
2
|
-
# outputs Exchange Web Services Restriction XML
|
3
|
-
#
|
4
|
-
#
|
5
1
|
module Rews
|
2
|
+
# models Restrictions for <tt>find_*</tt> operations
|
3
|
+
# on <tt>Folder::BaseFolderId</tt>
|
4
|
+
#
|
5
|
+
# takes restrictions written in Ruby s-expressions and
|
6
|
+
# outputs Exchange Web Services Restriction XML. e.g.
|
7
|
+
#
|
8
|
+
# <tt>[[:and, [:==, "item:Subject", "hello"], [:>=, "item:DateTimeSent", DateTime.parse("2011-03-16T15:57:37+00:00")]]</tt>
|
6
9
|
class Restriction
|
7
10
|
|
8
11
|
attr_reader :expr
|
@@ -12,7 +15,7 @@ module Rews
|
|
12
15
|
end
|
13
16
|
|
14
17
|
def inspect
|
15
|
-
"
|
18
|
+
"#<#{self.class} @expr=#{@expr.inspect}>"
|
16
19
|
end
|
17
20
|
|
18
21
|
def to_xml
|
@@ -81,7 +84,9 @@ module Rews
|
|
81
84
|
}
|
82
85
|
def write_logical(xml, expr)
|
83
86
|
xml.t LOGICAL_OPS[expr[0]] do
|
84
|
-
|
87
|
+
expr[1..-1].each do |clause|
|
88
|
+
Xml::write_expr(xml, clause)
|
89
|
+
end
|
85
90
|
end
|
86
91
|
end
|
87
92
|
end
|
data/lib/rews/shape.rb
CHANGED
@@ -24,9 +24,15 @@ module Rews
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# models ItemShape and FolderShape used in <tt>Folder::BaseFolderId.find_*</tt> and
|
28
|
+
# <tt>Folder::BaseFolderId.get_*</tt> methods
|
27
29
|
class Base
|
28
30
|
include Util
|
29
31
|
attr_reader :shape
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<#{self.class} @shape=#{@shape}>"
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
ITEM_SHAPE_OPTS = {
|
@@ -35,6 +41,8 @@ module Rews
|
|
35
41
|
:additional_properties=>nil
|
36
42
|
}
|
37
43
|
|
44
|
+
# models ItemShape used in <tt>Folder::BaseFolderId.find_item</tt> and
|
45
|
+
# <tt>Folder::BaseFolderId.get_item</tt> methods
|
38
46
|
class ItemShape < Base
|
39
47
|
def initialize(shape)
|
40
48
|
@shape = check_opts(ITEM_SHAPE_OPTS, shape)
|
@@ -54,6 +62,7 @@ module Rews
|
|
54
62
|
:additional_properties=>nil
|
55
63
|
}
|
56
64
|
|
65
|
+
# models +FolderShape+ used in <tt>Folder::BaseFolderId.find_folder</tt> method
|
57
66
|
class FolderShape < Base
|
58
67
|
def initialize(shape)
|
59
68
|
@shape = check_opts(FOLDER_SHAPE_OPTS, shape)
|
data/lib/rews/sort_order.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
# takes sort_orders written in Ruby s-expressions and
|
2
|
-
# outputs EWS SortOrder XML
|
3
1
|
module Rews
|
2
|
+
# models SortOrder used in <tt>Folder::BaseFolderId.find_*</tt> methods
|
3
|
+
#
|
4
|
+
# takes sort_orders written in Ruby s-expressions and
|
5
|
+
# outputs EWS SortOrder XML e.g.
|
6
|
+
#
|
7
|
+
# <tt>[["item:DateTimeReceived", "Ascending"], ["item:Size", "Descending"]]</tt>
|
4
8
|
class SortOrder
|
5
9
|
attr_reader :expr
|
6
10
|
|
@@ -9,7 +13,7 @@ module Rews
|
|
9
13
|
end
|
10
14
|
|
11
15
|
def inspect
|
12
|
-
"
|
16
|
+
"#<#{self.class} @expr=#{@expr.inspect}>"
|
13
17
|
end
|
14
18
|
|
15
19
|
def to_xml
|
data/lib/rews/util.rb
CHANGED
@@ -6,10 +6,10 @@ module Rews
|
|
6
6
|
|
7
7
|
# validates an options hash against a constraints hash
|
8
8
|
# in the constraints hash :
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
9
|
+
# * keys ending in ! indicate option is required
|
10
|
+
# * keys not ending in ! indicate option is not required
|
11
|
+
# * non-nil values provide defaults
|
12
|
+
# * hash values provide constraints for sub-hashes
|
13
13
|
def check_opts(constraints, opts={}, prefix=nil)
|
14
14
|
required_keys = Hash[constraints.keys.select{|k| k.to_s[-1..-1] == '!'}.map{|k| [strip_bang(k),k]}]
|
15
15
|
optional_keys = constraints.keys.select{|k| k.to_s[-1..-1] != '!'}
|
@@ -30,10 +30,11 @@ module Rews
|
|
30
30
|
raise "required options not given: #{required_keys.keys.map{|k| [prefix,k].compact.join('.')}.join(", ")}" if required_keys.size>0
|
31
31
|
|
32
32
|
# defaults
|
33
|
-
optional_keys.each{|k| opts[k] = constraints[k] if !constraints[k].is_a?(Hash)}
|
33
|
+
optional_keys.each{|k| opts[k] = constraints[k] if constraints[k] && !constraints[k].is_a?(Hash)}
|
34
34
|
opts
|
35
35
|
end
|
36
36
|
|
37
|
+
# strip a ! from the end of a +String+ or +Symbol+
|
37
38
|
def strip_bang(k)
|
38
39
|
if k.is_a? Symbol
|
39
40
|
k.to_s[0...-1].to_sym
|
@@ -42,14 +43,19 @@ module Rews
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
46
|
+
# camel-case a +String+
|
45
47
|
def camelize(s)
|
46
48
|
s.split('_').map(&:capitalize).join
|
47
49
|
end
|
48
50
|
|
51
|
+
# camel-case the keys of a +Hash+
|
49
52
|
def camel_keys(h)
|
50
53
|
Hash[h.map{|k,v| [camelize(k.to_s), v]}]
|
51
54
|
end
|
52
55
|
|
56
|
+
# check the response codes of an Exchange Web Services request.
|
57
|
+
# the supplied block makes a SOAP request, and the response is parsed
|
58
|
+
# out and checked
|
53
59
|
def with_error_check(client, *response_msg_keys)
|
54
60
|
raise "no block" if !block_given?
|
55
61
|
|
@@ -69,6 +75,7 @@ module Rews
|
|
69
75
|
statuses
|
70
76
|
end
|
71
77
|
|
78
|
+
# check the status of the response of a single part of a multi-part request
|
72
79
|
def single_error_check(client, status)
|
73
80
|
begin
|
74
81
|
response_class = status[:response_class]
|
@@ -77,9 +84,9 @@ module Rews
|
|
77
84
|
end
|
78
85
|
|
79
86
|
if status[:response_class] == "Error"
|
80
|
-
return "
|
87
|
+
return "#{status[:response_code]} - #{status[:message_text]}"
|
81
88
|
elsif status[:response_class] == "Warning"
|
82
|
-
client.log{|logger| logger.warn("#{status[:message_text]}")}
|
89
|
+
client.log{|logger| logger.warn("#{status[:response_code]} - #{status[:message_text]}")}
|
83
90
|
end
|
84
91
|
end
|
85
92
|
end
|
data/lib/rews/view.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Rews
|
2
|
+
# models IndexedPageItemView and IndexedPageFolderView definitions used by
|
3
|
+
# <tt>Folder::BaseFolderId.find_*</tt> methods
|
2
4
|
module View
|
3
5
|
module Xml
|
4
6
|
module_function
|
@@ -16,10 +18,15 @@ module Rews
|
|
16
18
|
include Util
|
17
19
|
|
18
20
|
attr_reader :view
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<#{self.class} @view=#{@view.inspect}>"
|
24
|
+
end
|
19
25
|
end
|
20
26
|
|
21
27
|
INDEXED_PAGE_VIEW_OPTS = {:max_entries_returned=>nil, :offset=>0, :base_point=>:Beginning}
|
22
28
|
|
29
|
+
# models the IndexedPageItemView used in <tt>Folder::BaseFolderId.find_item</tt> method
|
23
30
|
class IndexedPageItemView < Base
|
24
31
|
def initialize(view)
|
25
32
|
@view = check_opts(INDEXED_PAGE_VIEW_OPTS, view)
|
@@ -30,6 +37,7 @@ module Rews
|
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
40
|
+
# models the IndexedPageFolderView used in <tt>Folder::BaseFolderId.find_folder</tt> methods
|
33
41
|
class IndexedPageFolderView < Base
|
34
42
|
def initialize(view)
|
35
43
|
@view = check_opts(INDEXED_PAGE_VIEW_OPTS, view)
|