Class: Viewpoint::EWS::GenericFolder
- Inherits:
-
Object
- Object
- Viewpoint::EWS::GenericFolder
- Defined in:
- lib/model/generic_folder.rb
Overview
This class is a generic folder that should typically not be instantiated on it’s own. It represents all the commonalities among folders found in the Exchange Data Store of which there are many.
Direct Known Subclasses
CalendarFolder, ContactsFolder, Folder, SearchFolder, TasksFolder
Constant Summary collapse
- @@distinguished_folder_ids =
%w{calendar contacts deleteditems drafts inbox journal notes outbox sentitems tasks msgfolderroot root junkemail searchfolders voicemail recoverableitemsroot recoverableitemsdeletions recoverableitemsversions recoverableitemspurges archiveroot archivemsgfolderroot archivedeleteditems archiverecoverableitemsroot archiverecoverableitemsdeletions archiverecoverableitemsversions archiverecoverableitemspurges publicfoldersroot}
- @@event_types =
%w{CopiedEvent CreatedEvent DeletedEvent ModifiedEvent MovedEvent NewMailEvent}
Instance Attribute Summary collapse
-
#change_key ⇒ Object
Returns the value of attribute change_key.
-
#folder_id ⇒ Object
(also: #id)
Returns the value of attribute folder_id.
-
#parent_id ⇒ Object
Returns the value of attribute parent_id.
-
#subscription_id ⇒ Object
readonly
Returns the value of attribute subscription_id.
-
#sync_state ⇒ Object
Returns the value of attribute sync_state.
-
#watermark ⇒ Object
readonly
Returns the value of attribute watermark.
Attributes included from Model
#ews_methods, #ews_methods_undef
Class Method Summary collapse
-
.find_folders(root = :msgfolderroot, traversal = 'Shallow', shape = 'Default', folder_type = nil) ⇒ Array
Find subfolders of the passed root folder.
-
.folder_names(root = :msgfolderroot) ⇒ Array<String>
Return a list of folder names.
-
.get_folder(folder_id, act_as = nil, folder_shape = {:base_shape => 'Default'}) ⇒ Object
Get a specific folder by its ID.
-
.get_folder_by_name(name, root = :msgfolderroot, shape = 'Default', opts = {}) ⇒ GenericFolder
Gets a folder by name.
-
.get_folder_by_path(path, root = :msgfolderroot, shape = 'Default') ⇒ GenericFolder
Gets a folder by the given path.
Instance Method Summary collapse
-
#add_subfolder(name) ⇒ Object
Create a subfolder of this folder.
-
#clear_sync_state! ⇒ Object
Clears out the @sync_state so you can freshly synchronize this folder if needed.
-
#delete!(recycle_bin = false) ⇒ TrueClass
Deletes this folder from the Exchange Data Store.
-
#find_items(opts = {}) ⇒ Object
Find Items.
-
#get_events ⇒ Object
Checks a subscribed folder for events.
-
#get_item(item_id, change_key = nil) ⇒ Object
Get Item.
-
#get_items(item_ids, change_key = nil, options = {}) ⇒ Object
Get Items.
-
#initialize(ews_item) ⇒ GenericFolder
constructor
A new instance of GenericFolder.
-
#items_between(start_date, end_date, opts = {}) ⇒ Object
Fetch items between a given time period.
-
#items_since(date_time, opts = {}) ⇒ Object
Fetch items since a give DateTime.
-
#search_by_subject(match_str, exclude_str = nil) ⇒ Object
Search on the item subject.
-
#subscribe(event_types = @@event_types) ⇒ Boolean
Subscribe this folder to events.
-
#subscribed? ⇒ Boolean
Check if there is a subscription for this folder.
-
#sync_items!(sync_amount = 256, sync_all = false, opts = {}) ⇒ Hash
Syncronize Items in this folder.
-
#sync_items_since!(datetime, opts = {}) ⇒ Array<Item>
This is basically a work-around for Microsoft’s BPOS hosted Exchange, which does not support subscriptions at the time of this writing.
-
#todays_items(opts = {}) ⇒ Object
Fetch only items from today (since midnight).
-
#unsubscribe ⇒ Boolean
Unsubscribe this folder from further Exchange events.
Constructor Details
#initialize(ews_item) ⇒ GenericFolder
Returns a new instance of GenericFolder.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/model/generic_folder.rb', line 160 def initialize(ews_item) super() # Calls initialize in Model (creates @ews_methods Array) @ews_item = ews_item @folder_id = ews_item[:folder_id][:id] @ews_methods << :folder_id @ews_methods << :id @change_key = ews_item[:folder_id][:change_key] @ews_methods << :change_key unless ews_item[:parent_folder_id].nil? @parent_id = ews_item[:parent_folder_id] @ews_methods << :parent_id end define_str_var :display_name, :folder_class define_int_var :child_folder_count, :total_count # @todo Handle: # <EffectiveRights/>, <ExtendedProperty/>, <ManagedFolderInformation/>, <PermissionSet/> @sync_state = nil # Base-64 encoded sync data @synced = false # Whether or not the synchronization process is complete @subscription_id = nil @watermark = nil @shallow = true end |
Instance Attribute Details
#change_key ⇒ Object
Returns the value of attribute change_key.
156 157 158 |
# File 'lib/model/generic_folder.rb', line 156 def change_key @change_key end |
#folder_id ⇒ Object Also known as: id
Returns the value of attribute folder_id.
156 157 158 |
# File 'lib/model/generic_folder.rb', line 156 def folder_id @folder_id end |
#parent_id ⇒ Object
Returns the value of attribute parent_id.
156 157 158 |
# File 'lib/model/generic_folder.rb', line 156 def parent_id @parent_id end |
#subscription_id ⇒ Object (readonly)
Returns the value of attribute subscription_id.
157 158 159 |
# File 'lib/model/generic_folder.rb', line 157 def subscription_id @subscription_id end |
#sync_state ⇒ Object
Returns the value of attribute sync_state.
156 157 158 |
# File 'lib/model/generic_folder.rb', line 156 def sync_state @sync_state end |
#watermark ⇒ Object (readonly)
Returns the value of attribute watermark.
157 158 159 |
# File 'lib/model/generic_folder.rb', line 157 def watermark @watermark end |
Class Method Details
.find_folders(root = :msgfolderroot, traversal = 'Shallow', shape = 'Default', folder_type = nil) ⇒ Array
Find subfolders of the passed root folder. If no parameters are passed this method will search from the Root folder.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/model/generic_folder.rb', line 68 def self.find_folders(root = :msgfolderroot, traversal = 'Shallow', shape = 'Default', folder_type = nil) if( folder_type.nil? ) resp = (Viewpoint::EWS::EWS.instance).ews.find_folder( [normalize_id(root)], traversal, {:base_shape => shape} ) else restr = {:restriction => {:is_equal_to => [{:field_uRI => {:field_uRI=>'folder:FolderClass'}}, {:field_uRI_or_constant=>{:constant => {:value => folder_type}}}]} } resp = (Viewpoint::EWS::EWS.instance).ews.find_folder( [normalize_id(root)], traversal, {:base_shape => shape}, restr) end if(resp.status == 'Success') folders = [] resp.items.each do |f| f_type = f.keys.first.to_s.camel_case folders << (eval "#{f_type}.new(f[f.keys.first])") end return folders else raise EwsError, "Could not retrieve folders. #{resp.code}: #{resp.}" end end |
.folder_names(root = :msgfolderroot) ⇒ Array<String>
Return a list of folder names
95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/model/generic_folder.rb', line 95 def self.folder_names(root = :msgfolderroot) resp = (Viewpoint::EWS::EWS.instance).ews.find_folder([:msgfolderroot], 'Shallow') if(resp.status == 'Success') flds = [] resp.items.each do |f| flds << f[f.keys.first][:display_name][:text] end flds else raise EwsError, "Could not retrieve folders. #{resp.code}: #{resp.}" end end |
.get_folder(folder_id, act_as = nil, folder_shape = {:base_shape => 'Default'}) ⇒ Object
Get a specific folder by its ID.
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/model/generic_folder.rb', line 48 def self.get_folder(folder_id, act_as = nil, folder_shape = {:base_shape => 'Default'}) resp = (Viewpoint::EWS::EWS.instance).ews.get_folder( [normalize_id(folder_id)], folder_shape, act_as ) if(resp.status == 'Success') folder = resp.items.first f_type = folder.keys.first.to_s.camel_case return(eval "#{f_type}.new(folder[folder.keys.first])") else raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.}" end end |
.get_folder_by_name(name, root = :msgfolderroot, shape = 'Default', opts = {}) ⇒ GenericFolder
Gets a folder by name. This name must match the folder name exactly.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/model/generic_folder.rb', line 116 def self.get_folder_by_name(name, root = :msgfolderroot, shape = 'Default', opts = {}) opts[:traversal] = 'Deep' unless opts.has_key?(:traversal) # For now the :field_uRI and :field_uRI_or_constant must be in an Array for Ruby 1.8.7 because Hashes # are not positional at insertion until 1.9 restr = {:restriction => {:is_equal_to => [{:field_uRI => {:field_uRI=>'folder:DisplayName'}}, {:field_uRI_or_constant =>{:constant => {:value=>name}}}]}} resp = (Viewpoint::EWS::EWS.instance).ews.find_folder([root], opts[:traversal], {:base_shape => shape}, restr) if(resp.status == 'Success') raise EwsFolderNotFound, "The folder requested is invalid or unavailable" if resp.items.empty? f = resp.items.first f_type = f.keys.first.to_s.camel_case eval "#{f_type}.new(f[f.keys.first])" else raise EwsError, "Could not retrieve folder. #{resp.code}: #{resp.}" end end |
.get_folder_by_path(path, root = :msgfolderroot, shape = 'Default') ⇒ GenericFolder
Gets a folder by the given path. The default search path is :msgfolderroot so if you want to specify a path at a different root change that parameter.
144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/model/generic_folder.rb', line 144 def self.get_folder_by_path(path, root = :msgfolderroot, shape = 'Default') parts = path.split(/\//) parts = parts.slice(1..(parts.length)) if parts.first.empty? retfld = nil parts.each do |p| fld = self.get_folder_by_name(p, root, shape, {:traversal => 'Shallow'}) root = fld.id retfld = fld if(fld.display_name.downcase == p.downcase) end retfld end |
Instance Method Details
#add_subfolder(name) ⇒ Object
Create a subfolder of this folder
431 432 433 434 435 436 |
# File 'lib/model/generic_folder.rb', line 431 def add_subfolder(name) resp = (Viewpoint::EWS::EWS.instance).ews.create_folder(@folder_id, name) folder = resp.items.first ftype = folder.keys.first GenericFolder.get_folder(folder[ftype][:folder_id][:id]) end |
#clear_sync_state! ⇒ Object
Clears out the @sync_state so you can freshly synchronize this folder if needed
424 425 426 |
# File 'lib/model/generic_folder.rb', line 424 def clear_sync_state! @sync_state = nil end |
#delete!(recycle_bin = false) ⇒ TrueClass
Deletes this folder from the Exchange Data Store
442 443 444 445 446 |
# File 'lib/model/generic_folder.rb', line 442 def delete!(recycle_bin = false) deltype = recycle_bin ? 'MoveToDeletedItems' : 'HardDelete' resp = (Viewpoint::EWS::EWS.instance).ews.delete_folder(@folder_id, deltype) true end |
#find_items(opts = {}) ⇒ Object
Find Items
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/model/generic_folder.rb', line 249 def find_items(opts = {}) opts = opts.clone # clone the passed in object so we don't modify it in case it's being used in a loop item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : {:base_shape => 'Default'} unless item_shape.has_key?(:additional_properties) # Don't overwrite if specified by caller item_shape[:additional_properties] = {:field_uRI => ['item:ParentFolderId']} end resp = (Viewpoint::EWS::EWS.instance).ews.find_item([@folder_id], 'Shallow', item_shape, opts) if(resp.status == 'Success') parms = resp.items.shift items = [] resp.items.each do |i| i_type = i.keys.first items << (eval "#{i_type.to_s.camel_case}.new(i[i_type])") end return items else raise EwsError, "Could not find items. #{resp.code}: #{resp.}" end end |
#get_events ⇒ Object
check for subscription expiry
Checks a subscribed folder for events
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/model/generic_folder.rb', line 231 def get_events begin if(subscribed?) resp = (Viewpoint::EWS::EWS.instance).ews.get_events(@subscription_id, @watermark) parms = resp.items.shift @watermark = parms[:watermark] # @todo if parms[:more_events] # get more events return resp.items else raise StandardError, "Folder <#{self.display_name}> not subscribed to. Issue a Folder#subscribe before checking events." end rescue EwsSubscriptionTimeout => e @subscription_id, @watermark = nil, nil raise e end end |
#get_item(item_id, change_key = nil) ⇒ Object
Get Item
337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/model/generic_folder.rb', line 337 def get_item(item_id, change_key = nil) item_shape = {:base_shape => 'Default', :additional_properties => {:field_uRI => ['item:ParentFolderId']}} resp = (Viewpoint::EWS::EWS.instance).ews.get_item([item_id], item_shape) if(resp.status == 'Success') item = resp.items.shift type = item.keys.first eval "#{type.to_s.camel_case}.new(item[type])" else raise EwsError, "Could not retrieve item. #{resp.code}: #{resp.}" end end |
#get_items(item_ids, change_key = nil, options = {}) ⇒ Object
Get Items
356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
# File 'lib/model/generic_folder.rb', line 356 def get_items(item_ids, change_key = nil, ={}) item_shape = [:item_shape] || {:base_shape => 'Default', :additional_properties => {:field_uRI => ['item:ParentFolderId']}} shallow = item_shape[:base_shape] != 'AllProperties' resp = (Viewpoint::EWS::EWS.instance).ews.get_item(item_ids, item_shape) if(resp.status == 'Success') resp.items.map do |item| type = item.keys.first eval "#{type.to_s.camel_case}.new(item[type], :shallow => #{shallow})" end else raise EwsError, "Could not retrieve items. #{resp.code}: #{resp.}" end end |
#items_between(start_date, end_date, opts = {}) ⇒ Object
Fetch items between a given time period
290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/model/generic_folder.rb', line 290 def items_between(start_date, end_date, opts={}) restr = {:restriction => {:and => [ {:is_greater_than_or_equal_to => [{:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, {:field_uRI_or_constant=>{:constant => {:value =>start_date}}}]}, {:is_less_than_or_equal_to => [{:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, {:field_uRI_or_constant=>{:constant => {:value =>end_date}}}]} ]}} find_items(opts.merge(restr)) end |
#items_since(date_time, opts = {}) ⇒ Object
Fetch items since a give DateTime
278 279 280 281 282 283 284 285 |
# File 'lib/model/generic_folder.rb', line 278 def items_since(date_time, opts = {}) restr = {:restriction => {:is_greater_than_or_equal_to => [{:field_uRI => {:field_uRI=>'item:DateTimeReceived'}}, {:field_uRI_or_constant =>{:constant => {:value=>date_time}}}] }} find_items(opts.merge(restr)) end |
#search_by_subject(match_str, exclude_str = nil) ⇒ Object
Search on the item subject
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/model/generic_folder.rb', line 306 def search_by_subject(match_str, exclude_str = nil) match = {:contains => { :containment_mode => 'Substring', :containment_comparison => 'IgnoreCase', :field_uRI => {:field_uRI=>'item:Subject'}, :constant => {:value =>match_str} } } unless exclude_str.nil? excl = {:not => {:contains => { :containment_mode => 'Substring', :containment_comparison => 'IgnoreCase', :field_uRI => {:field_uRI=>'item:Subject'}, :constant => {:value =>exclude_str} } } } match[:and] = [{:contains => match.delete(:contains)}, excl] end find_items({:restriction => match}) end |
#subscribe(event_types = @@event_types) ⇒ Boolean
Add custom Exception for EWS
Subscribe this folder to events. This method initiates an Exchange pull type subscription.
192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/model/generic_folder.rb', line 192 def subscribe(event_types = @@event_types) # Refresh the subscription if already subscribed unsubscribe if subscribed? resp = (Viewpoint::EWS::EWS.instance).ews.subscribe([folder_id],event_types) if(resp.status == 'Success') @subscription_id = resp.items.first[:subscription_id][:text] @watermark = resp.items.first[:watermark][:text] return true else raise StandardError, "Error: #{resp.}" end end |
#subscribed? ⇒ Boolean
Check if there is a subscription for this folder.
208 209 210 |
# File 'lib/model/generic_folder.rb', line 208 def subscribed? ( @subscription_id.nil? or @watermark.nil? )? false : true end |
#sync_items!(sync_amount = 256, sync_all = false, opts = {}) ⇒ Hash
Syncronize Items in this folder. If this method is issued multiple times it will continue where the last sync completed.
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/model/generic_folder.rb', line 384 def sync_items!(sync_amount = 256, sync_all = false, opts = {}) item_shape = opts.has_key?(:item_shape) ? opts.delete(:item_shape) : {:base_shape => 'Default'} resp = (Viewpoint::EWS::EWS.instance).ews.sync_folder_items(@folder_id, @sync_state, sync_amount, item_shape) parms = resp.items.shift @sync_state = parms[:sync_state] @synced = parms[:includes_last_item_in_range] items = {} resp.items.each do |i| key = i.keys.first items[key] = [] unless items[key].is_a?(Array) if(key == :delete || key == :read_flag_change) items[key] << i[key][:item_id] else i_type = i[key].keys.first items[key] << (eval "#{i_type.to_s.camel_case}.new(i[key][i_type])") end end items end |
#sync_items_since!(datetime, opts = {}) ⇒ Array<Item>
This is basically a work-around for Microsoft’s BPOS hosted Exchange, which does not support subscriptions at the time of this writing. This is the best way I could think of to get items from a specific period of time and track changes. !! Before using this method I would suggest trying a GenericFolder#items_since then using a subscription to track changes. This method should be followed by subsequent calls to GenericFolder#sync_items! to fetch additional items. Calling this method again will clear the sync_state and synchronize everything again.
413 414 415 416 417 418 419 420 421 |
# File 'lib/model/generic_folder.rb', line 413 def sync_items_since!(datetime, opts={}) clear_sync_state! begin items = sync_items! end until items.empty? items_since(datetime, opts) end |
#todays_items(opts = {}) ⇒ Object
Fetch only items from today (since midnight)
270 271 272 273 274 |
# File 'lib/model/generic_folder.rb', line 270 def todays_items(opts = {}) #opts = {:query_string => ["Received:today"]} #This is a bit convoluted for pre-1.9.x ruby versions that don't support to_datetime items_since(DateTime.parse(Date.today.to_s), opts) end |
#unsubscribe ⇒ Boolean
Add custom Exception for EWS
Unsubscribe this folder from further Exchange events.
216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/model/generic_folder.rb', line 216 def unsubscribe return true if @subscription_id.nil? resp = (Viewpoint::EWS::EWS.instance).ews.unsubscribe(@subscription_id) if(resp.status == 'Success') @subscription_id, @watermark = nil, nil return true else raise StandardError, "Error: #{resp.}" end end |