rews 0.2.12 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,15 +29,20 @@ to use :
29
29
  :indexed_page_item_view=>{:max_entries_returned=>10, :offset=>0})
30
30
 
31
31
  # get some properties for a bunch of messages in one hit
32
- messages = inbox.get_item(mids, :item_shape=>{
33
- :base_shape=>:IdOnly,
34
- :additional_properties=>[
35
- [:field_uri, "item:Subject"],
36
- [:field_uri, "item:DateTimeReceived"],
37
- [:field_uri, "message:InternetMessageId"]]})
32
+ messages = c.get_item(mids, :item_shape=>{
33
+ :base_shape=>:IdOnly,
34
+ :additional_properties=>[
35
+ [:field_uri, "item:Subject"],
36
+ [:field_uri, "item:DateTimeReceived"],
37
+ [:field_uri, "message:InternetMessageId"],
38
+ [:field_uri, "message:IsRead"],
39
+ [:field_uri, "message:IsReadReceiptRequested"]]})
40
+
41
+ # suppress read receipts on any messages which have requested them
42
+ c.suppress_read_receipt(messages)
38
43
 
39
44
  # delete the items to the DeletedItems folder
40
- inbox.delete_item(mids, :delete_type=>:MoveToDeletedItems)
45
+ c.delete_item(mids, :delete_type=>:MoveToDeletedItems)
41
46
 
42
47
  == Install
43
48
 
data/Rakefile CHANGED
@@ -13,10 +13,12 @@ begin
13
13
  gem.add_dependency "savon", ">= 0.8.6"
14
14
  gem.add_dependency "ntlm-http", ">= 0.1.2"
15
15
  gem.add_dependency "fetch_in", ">= 0.2.0"
16
+ gem.add_runtime_dependency "rsxml", ">= 0.1.4"
16
17
  gem.add_development_dependency "httpclient", ">= 2.1.7"
17
18
  gem.add_development_dependency "rspec", ">= 1.2.9"
18
19
  gem.add_development_dependency "rr", ">= 0.10.5"
19
20
  gem.add_development_dependency "nokogiri", ">= 1.4.4"
21
+
20
22
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
23
  end
22
24
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.12
1
+ 0.5.0
@@ -4,18 +4,36 @@ require 'net/ntlm'
4
4
  # require 'httpclient' # don't need httpclient now ntlm-http is fixed too
5
5
  require 'savon'
6
6
  require 'fetch_in'
7
+ require 'rsxml'
7
8
 
8
9
  # Ruby Exchange Web Services
9
10
  module Rews
10
11
  WSDL = File.expand_path("../../Services.wsdl", __FILE__)
11
12
  SCHEMA_MESSAGES = "http://schemas.microsoft.com/exchange/services/2006/messages"
12
13
  SCHEMA_TYPES = "http://schemas.microsoft.com/exchange/services/2006/types"
14
+
15
+ class << self
16
+ attr_accessor :logdev
17
+ end
18
+
19
+ module_function
20
+
21
+ def logger
22
+ return @logger if @logger
23
+ @logger = Logger.new(logdev) if logdev
24
+ end
25
+
26
+ def log
27
+ yield(logger) if logger
28
+ nil
29
+ end
13
30
  end
14
31
 
15
32
  require 'rews/util'
16
33
  require 'rews/restriction'
17
34
  require 'rews/shape'
18
35
  require 'rews/sort_order'
36
+ require 'rews/update'
19
37
  require 'rews/view'
20
38
  require 'rews/folder'
21
39
  require 'rews/item'
@@ -1,11 +1,12 @@
1
1
  module Rews
2
2
  class Client
3
+ include Util
4
+
3
5
  attr_reader :endpoint
4
6
  attr_reader :auth_type
5
7
  attr_reader :user
6
8
  attr_reader :password
7
9
  attr_reader :savon_client
8
- attr_accessor :logdev
9
10
 
10
11
  # create a +Client+ to access Exchange Web Services
11
12
  # * using NTLM authentication
@@ -39,14 +40,181 @@ module Rews
39
40
  Folder::DistinguishedFolderId.new(self, id, mailbox_email)
40
41
  end
41
42
 
42
- # yield a +Logger+ if +logdev+ has been set
43
- def log
44
- yield logger if @logdev
43
+ CREATE_ITEM_OPTS={
44
+ :items=>nil,
45
+ :message_disposition=>nil,
46
+ :send_meeting_invitations=>nil
47
+ }
48
+
49
+ # create items, specifying a list of Rsxml expressions, one for each item in the Items list e.g.
50
+ #
51
+ # client.create_item(:items=>[[:suppress_read_receipt, [:reference_item_id, {:id=>"abc", :change_key=>"def"}]]])
52
+ def create_item(opts={})
53
+ opts = check_opts(CREATE_ITEM_OPTS, opts)
54
+
55
+ items = opts[:items].compact if opts[:items]
56
+ raise "no items!" if items.empty?
57
+
58
+ attrs = {}
59
+ attrs[:message_disposition] = opts[:message_disposition] if opts[:message_disposition]
60
+ attrs[:send_meeting_invitations] = opts[:send_meeting_invitations] if opts[:send_meeting_invitations]
61
+
62
+ r = with_error_check(self, :create_item_response, :response_messages, :create_item_response_message) do
63
+ savon_client.request(:wsdl, "CreateItem", attrs) do
64
+ http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/CreateItem\"" # required by EWS 2007
65
+ soap.namespaces["xmlns:t"]=SCHEMA_TYPES
66
+
67
+ xml = Builder::XmlMarkup.new
68
+
69
+ xml.wsdl :Items do
70
+ items.each do |item|
71
+ xml << Util.rsxml_to_xml(item)
72
+ end
73
+ end
74
+
75
+ soap.body = xml.target!
76
+ end
77
+ end
78
+ r
79
+ end
80
+
81
+ # +iids+ is a list of Items or ItemIds. If +iids+ is a list of Items,
82
+ # and those Items have +IsRead+ or +IsReadReceiptRequested+ properties then
83
+ # no +SuppressReadReceipt+ Item will be created if ( +IsRead+=true or
84
+ # +IsReadReceiptRequested+=false)
85
+ def suppress_read_receipt(iids)
86
+ items = iids.map do |item_or_item_id|
87
+ item_id = item_or_item_id.is_a?(Item::Item) ? item_or_item_id.item_id : item_or_item_id
88
+ srr = [:suppress_read_receipt, [:reference_item_id, {:id=>item_id.id, :change_key=>item_id.change_key}]]
89
+ if item_or_item_id.is_a?(Item::Item)
90
+ attributes = item_or_item_id.attributes
91
+ if (attributes.has_key?(:is_read) && attributes[:is_read]) ||
92
+ (attributes.has_key?(:is_read_receipt_requested) &&
93
+ !attributes[:is_read_receipt_requested])
94
+ next
95
+ else
96
+ srr
97
+ end
98
+ else
99
+ srr
100
+ end
101
+ end.compact
102
+ create_item(:items=>items) if items.length>0
45
103
  end
46
104
 
47
- def logger
48
- return @logger if @logger
49
- @logger = Logger.new(@logdev) if @logdev
105
+ GET_ITEM_OPTS = {
106
+ :item_shape=>Shape::ITEM_SHAPE_OPTS,
107
+ :ignore_change_keys=>nil
108
+ }
109
+
110
+ # retrieve a bunch of <tt>Item::Item</tt>s in one API hit.
111
+ # takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
112
+ # or a <tt>Folder::FindResult</tt> and options to specify +Shape::ItemShape+
113
+ def get_item(message_ids, opts={})
114
+ opts = check_opts(GET_ITEM_OPTS, opts)
115
+ message_ids = message_ids.result if message_ids.is_a?(Folder::FindResult)
116
+
117
+ r = with_error_check(self, :get_item_response,:response_messages,:get_item_response_message) do
118
+ self.savon_client.request(:wsdl, "GetItem") do
119
+ http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/GetItem\"" # required by EWS 2007
120
+ soap.namespaces["xmlns:t"]=SCHEMA_TYPES
121
+
122
+ xml = Builder::XmlMarkup.new
123
+
124
+ xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
125
+ xml.wsdl :ItemIds do
126
+ message_ids.each do |mid|
127
+ mid = mid.item_id if mid.is_a?(Item::Item)
128
+ xml << mid.to_xml(opts[:ignore_change_keys])
129
+ end
130
+ end
131
+
132
+ soap.body = xml.target!
133
+ end
134
+ end
135
+ Item.read_get_item_response_messages(self, r)
50
136
  end
137
+
138
+
139
+
140
+ UPDATE_ITEM_OPTS = {
141
+ :conflict_resolution => "AutoResolve",
142
+ :message_disposition => "SaveOnly",
143
+ :ignore_change_keys=>false,
144
+ :updates => nil,
145
+ }
146
+
147
+ # bulk update a bunch of Items in one API hit
148
+ # takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
149
+ # or a <tt>Folder::FindResult</tt> and applies the same set of updates to each of them
150
+ def update_item(message_ids, opts={})
151
+ opts = check_opts(UPDATE_ITEM_OPTS, opts)
152
+ message_ids = message_ids.result if message_ids.is_a?(Folder::FindResult)
153
+
154
+ updates = [*opts[:updates]].compact
155
+ raise "no updates!" if updates.empty?
156
+ r = with_error_check(self, :update_item_response, :response_messages, :update_item_response_message) do
157
+ self.savon_client.request(:wsdl, "UpdateItem",
158
+ :ConflictResolution=>opts[:conflict_resolution],
159
+ :MessageDisposition=>opts[:message_disposition]) do
160
+ http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/UpdateItem\"" # required by EWS 2007
161
+ soap.namespaces["xmlns:t"]=SCHEMA_TYPES
162
+
163
+ xml = Builder::XmlMarkup.new
164
+
165
+ xml.wsdl :ItemChanges do
166
+ message_ids.each do |mid|
167
+ mid = mid.item_id if mid.is_a?(Item::Item)
168
+ xml.t :ItemChange do
169
+ xml << mid.to_xml(opts[:ignore_change_keys])
170
+ xml.t :Updates do
171
+ updates.each do |update|
172
+ xml << update.to_xml
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ soap.body = xml.target!
180
+ end
181
+ end
182
+ r
183
+ end
184
+
185
+ DELETE_ITEM_OPTS = {
186
+ :delete_type! =>nil,
187
+ :ignore_change_keys=>false
188
+ }
189
+
190
+ # delete a bunch of Items in one API hit.
191
+ # takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
192
+ # or a <tt>Folder::FindResult</tt> and options to specify DeleteType
193
+ def delete_item(message_ids, opts={})
194
+ opts = check_opts(DELETE_ITEM_OPTS, opts)
195
+ message_ids = message_ids.result if message_ids.is_a?(Folder::FindResult)
196
+
197
+ r = with_error_check(self, :delete_item_response, :response_messages, :delete_item_response_message) do
198
+ self.savon_client.request(:wsdl, "DeleteItem", :DeleteType=>opts[:delete_type]) do
199
+ http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/DeleteItem\"" # required by EWS 2007
200
+ soap.namespaces["xmlns:t"]=SCHEMA_TYPES
201
+
202
+ xml = Builder::XmlMarkup.new
203
+
204
+ xml.wsdl :ItemIds do
205
+ message_ids.each do |mid|
206
+ mid = mid.item_id if mid.is_a?(Item::Item)
207
+ xml << mid.to_xml(opts[:ignore_change_keys])
208
+ end
209
+ end
210
+
211
+ soap.body = xml.target!
212
+ end
213
+ end
214
+ true
215
+ end
216
+
217
+
218
+
51
219
  end
52
220
  end
@@ -189,70 +189,7 @@ module Rews
189
189
  r
190
190
  end
191
191
 
192
- GET_ITEM_OPTS = {
193
- :item_shape=>Shape::ITEM_SHAPE_OPTS,
194
- :ignore_change_keys=>nil
195
- }
196
-
197
- # retrieve a bunch of <tt>Item::Item</tt>s in one API hit.
198
- # takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
199
- # or a <tt>Folder::FindResult</tt> and options to specify +Shape::ItemShape+
200
- def get_item(message_ids, opts={})
201
- opts = check_opts(GET_ITEM_OPTS, opts)
202
- message_ids = message_ids.result if message_ids.is_a?(FindResult)
203
-
204
- r = with_error_check(client, :get_item_response,:response_messages,:get_item_response_message) do
205
- client.savon_client.request(:wsdl, "GetItem") do
206
- http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/GetItem\"" # required by EWS 2007
207
- soap.namespaces["xmlns:t"]=SCHEMA_TYPES
208
-
209
- xml = Builder::XmlMarkup.new
210
-
211
- xml << Shape::ItemShape.new(opts[:item_shape]||{}).to_xml
212
- xml.wsdl :ItemIds do
213
- message_ids.each do |mid|
214
- mid = mid.item_id if mid.is_a?(Item::Item)
215
- xml << mid.to_xml(opts[:ignore_change_keys])
216
- end
217
- end
218
-
219
- soap.body = xml.target!
220
- end
221
- end
222
- Item.read_get_item_response_messages(client, r)
223
- end
224
192
 
225
- DELETE_ITEM_OPTS = {
226
- :delete_type! =>nil,
227
- :ignore_change_keys=>false
228
- }
229
-
230
- # delete a bunch of Items in one API hit.
231
- # takes a list of <tt>Item::ItemId</tt>s, or a list of <tt>Item::Item</tt>,
232
- # or a <tt>Folder::FindResult</tt> and options to specify DeleteType
233
- def delete_item(message_ids, opts={})
234
- opts = check_opts(DELETE_ITEM_OPTS, opts)
235
- message_ids = message_ids.result if message_ids.is_a?(FindResult)
236
-
237
- r = with_error_check(client, :delete_item_response, :response_messages, :delete_item_response_message) do
238
- client.savon_client.request(:wsdl, "DeleteItem", :DeleteType=>opts[:delete_type]) do
239
- http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/DeleteItem\"" # required by EWS 2007
240
- soap.namespaces["xmlns:t"]=SCHEMA_TYPES
241
-
242
- xml = Builder::XmlMarkup.new
243
-
244
- xml.wsdl :ItemIds do
245
- message_ids.each do |mid|
246
- mid = mid.item_id if mid.is_a?(Item::Item)
247
- xml << mid.to_xml(opts[:ignore_change_keys])
248
- end
249
- end
250
-
251
- soap.body = xml.target!
252
- end
253
- end
254
- true
255
- end
256
193
  end
257
194
 
258
195
  # identifies a regular (non-distinguished) Folder on an Exchange server
@@ -32,7 +32,7 @@ module Rews
32
32
  @client = client
33
33
  @item_id = ItemId.new(client, attributes[:item_id])
34
34
  @item_class = item_class
35
- @attributes = attributes
35
+ @attributes = attributes || {}
36
36
  end
37
37
 
38
38
  def ==(other)
@@ -134,6 +134,51 @@ module Rews
134
134
  true
135
135
  end
136
136
 
137
+ UPDATE_ITEM_OPTS = {
138
+ :conflict_resolution => "AutoResolve",
139
+ :message_disposition => "SaveOnly",
140
+ :ignore_change_keys=>false,
141
+ :updates => nil,
142
+ }
143
+
144
+ def update_item(opts={})
145
+ opts = check_opts(UPDATE_ITEM_OPTS, opts)
146
+ updates = [*opts[:updates]].compact
147
+ raise "no updates!" if updates.empty?
148
+ r = with_error_check(client, :update_item_response, :response_messages, :update_item_response_message) do
149
+ client.savon_client.request(:wsdl, "UpdateItem",
150
+ :ConflictResolution=>opts[:conflict_resolution],
151
+ :MessageDisposition=>opts[:message_disposition]) do
152
+ http.headers["SOAPAction"] = "\"#{SCHEMA_MESSAGES}/UpdateItem\"" # required by EWS 2007
153
+ soap.namespaces["xmlns:t"]=SCHEMA_TYPES
154
+
155
+ xml = Builder::XmlMarkup.new
156
+
157
+ xml.wsdl :ItemChanges do
158
+ xml.t :ItemChange do
159
+ xml << self.to_xml(opts[:ignore_change_keys])
160
+ xml.t :Updates do
161
+ updates.each do |update|
162
+ xml << update.to_xml
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ soap.body = xml.target!
169
+ end
170
+ end
171
+ r
172
+ end
173
+
174
+ # sets message:isReadReceiptRequested and message:isDeliveryReceiptRequested
175
+ # properties of a message to false
176
+ def set_is_read(is_read=true)
177
+ update_item(:conflict_resolution=>"AlwaysOverwrite",
178
+ :message_disposition=>"SaveOnly",
179
+ :updates=>[SetItemField.new("message:IsRead", [:message,[:is_read, is_read.to_s]])])
180
+ end
181
+
137
182
  def to_xml(ignore_change_key=false)
138
183
  xml = Builder::XmlMarkup.new
139
184
  attrs = {:Id=>id.to_s}
@@ -0,0 +1,46 @@
1
+ module Rews
2
+ class Update
3
+ attr_reader :field_uri
4
+ attr_reader :item_expr
5
+
6
+ def initialize(field_uri, item_expr=nil)
7
+ @field_uri = field_uri
8
+ @item_expr = item_expr
9
+ end
10
+
11
+ def inspect
12
+ "#<#{Xml.update_tag(self.class)} @field_uri=#{@field_uri}, @item_expr=#{@item_expr.inspect}>"
13
+ end
14
+
15
+ def to_xml
16
+ Xml.write_update(self.class, field_uri, item_expr)
17
+ end
18
+
19
+ module Xml
20
+ module_function
21
+
22
+ def write_update(type, field_uri, item_expr)
23
+ xml = Builder::XmlMarkup.new
24
+ xml.t(update_tag(type)) do
25
+ xml.t :FieldURI, :FieldURI=>field_uri
26
+ xml << Util.rsxml_to_xml(item_expr)
27
+ end
28
+ xml.target!
29
+ end
30
+
31
+ def update_tag(type)
32
+ # final component of module scoped classname
33
+ type.to_s[/(?:^|::)([^:]+)$/, 1].to_sym
34
+ end
35
+ end
36
+ end
37
+
38
+ class SetItemField < Update
39
+ end
40
+
41
+ class AppendToItemField < Update
42
+ end
43
+
44
+ class DeleteItemField < Update
45
+ end
46
+ end