rews 0.2.12 → 0.5.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.
@@ -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