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}- @@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 ⇒ 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, shape = 'Default') ⇒ GenericFolder?
Gets a folder by name.
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.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/model/generic_folder.rb', line 130 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.
126 127 128 |
# File 'lib/model/generic_folder.rb', line 126 def change_key @change_key end |
#folder_id ⇒ Object Also known as: id
Returns the value of attribute folder_id.
126 127 128 |
# File 'lib/model/generic_folder.rb', line 126 def folder_id @folder_id end |
#parent_id ⇒ Object
Returns the value of attribute parent_id.
126 127 128 |
# File 'lib/model/generic_folder.rb', line 126 def parent_id @parent_id end |
#subscription_id ⇒ Object (readonly)
Returns the value of attribute subscription_id.
127 128 129 |
# File 'lib/model/generic_folder.rb', line 127 def subscription_id @subscription_id end |
#sync_state ⇒ Object
Returns the value of attribute sync_state.
126 127 128 |
# File 'lib/model/generic_folder.rb', line 126 def sync_state @sync_state end |
#watermark ⇒ Object (readonly)
Returns the value of attribute watermark.
127 128 129 |
# File 'lib/model/generic_folder.rb', line 127 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.message}" end end |
.folder_names ⇒ Array<String>
Return a list of folder names
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/model/generic_folder.rb', line 92 def self.folder_names 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.message}" end end |
.get_folder(folder_id, act_as = nil, folder_shape = {:base_shape => 'Default'}) ⇒ Object
Get a specific folder by its ID.
49 50 51 52 53 54 55 56 57 58 |
# File 'lib/model/generic_folder.rb', line 49 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.message}" end end |
.get_folder_by_name(name, shape = 'Default') ⇒ GenericFolder?
Gets a folder by name. This name must match the folder name exactly.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/model/generic_folder.rb', line 109 def self.get_folder_by_name(name, shape = 'Default') # 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], 'Deep', {:base_shape => shape}, restr) if(resp.status == 'Success') return nil 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.message}" end end |
Instance Method Details
#add_subfolder(name) ⇒ Object
Create a subfolder of this folder
401 402 403 404 405 406 |
# File 'lib/model/generic_folder.rb', line 401 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
394 395 396 |
# File 'lib/model/generic_folder.rb', line 394 def clear_sync_state! @sync_state = nil end |
#delete!(recycle_bin = false) ⇒ TrueClass
Deletes this folder from the Exchange Data Store
412 413 414 415 416 |
# File 'lib/model/generic_folder.rb', line 412 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
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/model/generic_folder.rb', line 219 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.message}" end end |
#get_events ⇒ Object
check for subscription expiry
Checks a subscribed folder for events
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/model/generic_folder.rb', line 201 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
307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/model/generic_folder.rb', line 307 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.message}" end end |
#get_items(item_ids, change_key = nil, options = {}) ⇒ Object
Get Items
326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/model/generic_folder.rb', line 326 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.message}" end end |
#items_between(start_date, end_date, opts = {}) ⇒ Object
Fetch items between a given time period
260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/model/generic_folder.rb', line 260 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
248 249 250 251 252 253 254 255 |
# File 'lib/model/generic_folder.rb', line 248 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
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/model/generic_folder.rb', line 276 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.
162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/model/generic_folder.rb', line 162 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.message}" end end |
#subscribed? ⇒ Boolean
Check if there is a subscription for this folder.
178 179 180 |
# File 'lib/model/generic_folder.rb', line 178 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.
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/model/generic_folder.rb', line 354 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.
383 384 385 386 387 388 389 390 391 |
# File 'lib/model/generic_folder.rb', line 383 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)
240 241 242 243 244 |
# File 'lib/model/generic_folder.rb', line 240 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.
186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/model/generic_folder.rb', line 186 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.message}" end end |