exchanger 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/lib/exchanger.rb +79 -0
- data/lib/exchanger/attributes.rb +61 -0
- data/lib/exchanger/boolean.rb +4 -0
- data/lib/exchanger/client.rb +19 -0
- data/lib/exchanger/config.rb +32 -0
- data/lib/exchanger/dirty.rb +239 -0
- data/lib/exchanger/element.rb +161 -0
- data/lib/exchanger/elements/attendee.rb +10 -0
- data/lib/exchanger/elements/base_folder.rb +61 -0
- data/lib/exchanger/elements/calendar_folder.rb +11 -0
- data/lib/exchanger/elements/calendar_item.rb +59 -0
- data/lib/exchanger/elements/complete_name.rb +16 -0
- data/lib/exchanger/elements/contact.rb +49 -0
- data/lib/exchanger/elements/contacts_folder.rb +17 -0
- data/lib/exchanger/elements/distribution_list.rb +8 -0
- data/lib/exchanger/elements/email_address.rb +16 -0
- data/lib/exchanger/elements/entry.rb +11 -0
- data/lib/exchanger/elements/folder.rb +9 -0
- data/lib/exchanger/elements/identifier.rb +7 -0
- data/lib/exchanger/elements/im_address.rb +20 -0
- data/lib/exchanger/elements/item.rb +86 -0
- data/lib/exchanger/elements/mailbox.rb +34 -0
- data/lib/exchanger/elements/meeting_cancellation.rb +4 -0
- data/lib/exchanger/elements/meeting_message.rb +16 -0
- data/lib/exchanger/elements/meeting_request.rb +6 -0
- data/lib/exchanger/elements/meeting_response.rb +4 -0
- data/lib/exchanger/elements/message.rb +24 -0
- data/lib/exchanger/elements/phone_number.rb +13 -0
- data/lib/exchanger/elements/physical_address.rb +15 -0
- data/lib/exchanger/elements/search_folder.rb +5 -0
- data/lib/exchanger/elements/single_recipient.rb +6 -0
- data/lib/exchanger/elements/task.rb +5 -0
- data/lib/exchanger/elements/tasks_folder.rb +4 -0
- data/lib/exchanger/field.rb +139 -0
- data/lib/exchanger/operation.rb +110 -0
- data/lib/exchanger/operations/create_item.rb +64 -0
- data/lib/exchanger/operations/expand_dl.rb +42 -0
- data/lib/exchanger/operations/find_folder.rb +55 -0
- data/lib/exchanger/operations/find_item.rb +54 -0
- data/lib/exchanger/operations/get_folder.rb +55 -0
- data/lib/exchanger/operations/get_item.rb +44 -0
- data/lib/exchanger/operations/resolve_names.rb +43 -0
- data/lib/exchanger/operations/update_item.rb +43 -0
- data/lib/exchanger/persistence.rb +27 -0
- data/spec/calendar_item_spec.rb +26 -0
- data/spec/client_spec.rb +11 -0
- data/spec/contact_spec.rb +68 -0
- data/spec/element_spec.rb +4 -0
- data/spec/field_spec.rb +118 -0
- data/spec/folder_spec.rb +13 -0
- data/spec/mailbox_spec.rb +9 -0
- data/spec/spec_helper.rb +6 -0
- metadata +208 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The CreateItem operation creates items in the Exchanger store.
|
3
|
+
#
|
4
|
+
# You can use the CreateItem operation to create the following:
|
5
|
+
# * Calendar items
|
6
|
+
# * E-mail messages
|
7
|
+
# * Meeting requests
|
8
|
+
# * Tasks
|
9
|
+
# * Contacts
|
10
|
+
#
|
11
|
+
# http://msdn.microsoft.com/en-us/library/aa563797.aspx
|
12
|
+
class CreateItem < Operation
|
13
|
+
class Request < Operation::Request
|
14
|
+
attr_accessor :folder_id, :email_address, :items
|
15
|
+
|
16
|
+
# Reset request options to defaults.
|
17
|
+
def reset
|
18
|
+
@folder_id = :contacts
|
19
|
+
@email_address = nil
|
20
|
+
@items = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_xml
|
24
|
+
Nokogiri::XML::Builder.new do |xml|
|
25
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"], "xmlns:t" => NS["t"], "xmlns:xsi" => NS["xsi"], "xmlns:xsd" => NS["xsd"]) do
|
26
|
+
xml.send("soap:Body") do
|
27
|
+
xml.CreateItem("xmlns" => NS["m"]) do
|
28
|
+
xml.SavedItemFolderId do
|
29
|
+
if folder_id.is_a?(Symbol)
|
30
|
+
xml.send("t:DistinguishedFolderId", "Id" => folder_id) do
|
31
|
+
if email_address
|
32
|
+
xml.send("t:Mailbox") do
|
33
|
+
xml.send("t:EmailAddress", email_address)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
xml.send("t:FolderId", "Id" => folder_id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
xml.Items do
|
42
|
+
items.each do |item|
|
43
|
+
item_xml = item.to_xml
|
44
|
+
item_xml.add_namespace_definition("t", NS["t"])
|
45
|
+
item_xml.namespace = item_xml.namespace_definitions[0]
|
46
|
+
xml << item_xml.to_s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Response < Operation::Response
|
57
|
+
def item_ids
|
58
|
+
to_xml.xpath(".//t:ItemId", NS).map do |node|
|
59
|
+
Identifier.new_from_xml(node)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The ExpandDL operation exposes the full membership of distribution lists.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa494152.aspx
|
5
|
+
class ExpandDL < Operation
|
6
|
+
class Request < Operation::Request
|
7
|
+
attr_accessor :mailbox
|
8
|
+
|
9
|
+
# Reset request options to defaults.
|
10
|
+
def reset
|
11
|
+
@mailbox = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml
|
15
|
+
Nokogiri::XML::Builder.new do |xml|
|
16
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
17
|
+
xml.send("soap:Body") do
|
18
|
+
xml.ExpandDL("xmlns" => NS["m"], "xmlns:t" => NS["t"]) do
|
19
|
+
xml.Mailbox do
|
20
|
+
if mailbox.item_id
|
21
|
+
xml.send("t:ItemId", "Id" => mailbox.item_id.id, "ChangeKey" => mailbox.item_id.change_key)
|
22
|
+
else
|
23
|
+
xml.send("t:EmailAddress", mailbox.email_address)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Response < Operation::Response
|
34
|
+
def mailboxes
|
35
|
+
to_xml.xpath(".//t:Mailbox", NS).map do |node|
|
36
|
+
item_klass = Exchanger.const_get(node.name)
|
37
|
+
item_klass.new_from_xml(node)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The FindFolder operation uses Exchanger Web Services to find subfolders of
|
3
|
+
# an identified folder and returns a set of properties that describe the set of subfolders.
|
4
|
+
#
|
5
|
+
# http://msdn.microsoft.com/en-us/library/aa563918.aspx
|
6
|
+
class FindFolder < Operation
|
7
|
+
class Request < Operation::Request
|
8
|
+
attr_accessor :parent_folder_id, :base_shape, :email_address, :traversal
|
9
|
+
|
10
|
+
# Reset request options to defaults.
|
11
|
+
def reset
|
12
|
+
@parent_folder_id = nil
|
13
|
+
@traversal = :shallow
|
14
|
+
@base_shape = :all_properties
|
15
|
+
@email_address = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_xml
|
19
|
+
Nokogiri::XML::Builder.new do |xml|
|
20
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
21
|
+
xml.send("soap:Body") do
|
22
|
+
xml.FindFolder("xmlns" => NS["m"], "xmlns:t" => NS["t"], "Traversal" => traversal.to_s.camelize) do
|
23
|
+
xml.FolderShape do
|
24
|
+
xml.send "t:BaseShape", base_shape.to_s.camelize
|
25
|
+
end
|
26
|
+
xml.ParentFolderIds do
|
27
|
+
if parent_folder_id.is_a?(Symbol)
|
28
|
+
xml.send("t:DistinguishedFolderId", "Id" => parent_folder_id) do
|
29
|
+
if email_address
|
30
|
+
xml.send("t:Mailbox") do
|
31
|
+
xml.send("t:EmailAddress", email_address)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
else
|
36
|
+
xml.send("t:FolderId", "Id" => parent_folder_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Response < Operation::Response
|
47
|
+
def folders
|
48
|
+
to_xml.xpath(".//t:Folders", NS).children.map do |node|
|
49
|
+
folder_klass = Exchanger.const_get(node.name)
|
50
|
+
folder_klass.new_from_xml(node)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The FindItem operation identifies items that are located in a specified folder.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa566107.aspx
|
5
|
+
class FindItem < Operation
|
6
|
+
class Request < Operation::Request
|
7
|
+
attr_accessor :folder_id, :traversal, :base_shape, :email_address
|
8
|
+
|
9
|
+
# Reset request options to defaults.
|
10
|
+
def reset
|
11
|
+
@folder_id = :contacts
|
12
|
+
@traversal = :shallow
|
13
|
+
@base_shape = :all_properties
|
14
|
+
@email_address = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_xml
|
18
|
+
Nokogiri::XML::Builder.new do |xml|
|
19
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
20
|
+
xml.send("soap:Body") do
|
21
|
+
xml.FindItem("xmlns" => NS["m"], "xmlns:t" => NS["t"], "Traversal" => traversal.to_s.camelize) do
|
22
|
+
xml.ItemShape do
|
23
|
+
xml.send "t:BaseShape", base_shape.to_s.camelize
|
24
|
+
end
|
25
|
+
xml.ParentFolderIds do
|
26
|
+
if folder_id.is_a?(Symbol)
|
27
|
+
xml.send("t:DistinguishedFolderId", "Id" => folder_id) do
|
28
|
+
if email_address
|
29
|
+
xml.send("t:Mailbox") do
|
30
|
+
xml.send("t:EmailAddress", email_address)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
xml.send("t:FolderId", "Id" => folder_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Response < Operation::Response
|
46
|
+
def items
|
47
|
+
to_xml.xpath(".//t:Items", NS).children.map do |node|
|
48
|
+
item_klass = Exchanger.const_get(node.name)
|
49
|
+
item_klass.new_from_xml(node)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The GetFolder operation gets folders from the Exchanger store.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa580274.aspx
|
5
|
+
class GetFolder < Operation
|
6
|
+
class Request < Operation::Request
|
7
|
+
attr_accessor :folder_ids, :base_shape, :email_address
|
8
|
+
|
9
|
+
# Reset request options to defaults.
|
10
|
+
def reset
|
11
|
+
@folder_ids = []
|
12
|
+
@base_shape = :default
|
13
|
+
@email_address = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_xml
|
17
|
+
Nokogiri::XML::Builder.new do |xml|
|
18
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
19
|
+
xml.send("soap:Body") do
|
20
|
+
xml.GetFolder("xmlns" => NS["m"], "xmlns:t" => NS["t"]) do
|
21
|
+
xml.FolderShape do
|
22
|
+
xml.send "t:BaseShape", base_shape.to_s.camelize
|
23
|
+
end
|
24
|
+
xml.FolderIds do
|
25
|
+
folder_ids.each do |folder_id|
|
26
|
+
if folder_id.is_a?(Symbol)
|
27
|
+
xml.send("t:DistinguishedFolderId", "Id" => folder_id) do
|
28
|
+
if email_address
|
29
|
+
xml.send("t:Mailbox") do
|
30
|
+
xml.send("t:EmailAddress", email_address)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
xml.send("t:FolderId", "Id" => folder_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Response < Operation::Response
|
47
|
+
def folders
|
48
|
+
to_xml.xpath(".//m:Folders", NS).children.map do |node|
|
49
|
+
folder_klass = Exchanger.const_get(node.name)
|
50
|
+
folder_klass.new_from_xml(node)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The GetItem operation gets items from the Exchanger store.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa565934.aspx
|
5
|
+
class GetItem < Operation
|
6
|
+
class Request < Operation::Request
|
7
|
+
attr_accessor :item_ids, :base_shape
|
8
|
+
|
9
|
+
# Reset request options to defaults.
|
10
|
+
def reset
|
11
|
+
@item_ids = []
|
12
|
+
@base_shape = :all_properties
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
Nokogiri::XML::Builder.new do |xml|
|
17
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
18
|
+
xml.send("soap:Body") do
|
19
|
+
xml.GetItem("xmlns" => NS["m"], "xmlns:t" => NS["t"]) do
|
20
|
+
xml.ItemShape do
|
21
|
+
xml.send "t:BaseShape", base_shape.to_s.camelize
|
22
|
+
end
|
23
|
+
xml.ItemIds do
|
24
|
+
item_ids.each do |item_id|
|
25
|
+
xml.send("t:ItemId", "Id" => item_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Response < Operation::Response
|
36
|
+
def items
|
37
|
+
to_xml.xpath(".//m:Items", NS).children.map do |node|
|
38
|
+
item_klass = Exchanger.const_get(node.name)
|
39
|
+
item_klass.new_from_xml(node)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The ResolveNames operation resolves ambiguous e-mail addresses and display names.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa563518.aspx
|
5
|
+
class ResolveNames < Operation
|
6
|
+
class Request < Operation::Request
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
# Reset request options to defaults.
|
10
|
+
def reset
|
11
|
+
@name = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_xml
|
15
|
+
Nokogiri::XML::Builder.new do |xml|
|
16
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"]) do
|
17
|
+
xml.send("soap:Body") do
|
18
|
+
xml.ResolveNames("xmlns" => NS["m"], "xmlns:t" => NS["t"], "ReturnFullContactData" => "true") do
|
19
|
+
xml.UnresolvedEntry name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Response < Operation::Response
|
28
|
+
def mailboxes
|
29
|
+
to_xml.xpath(".//t:Mailbox", NS).map do |node|
|
30
|
+
item_klass = Exchanger.const_get(node.name)
|
31
|
+
item_klass.new_from_xml(node)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def contacts
|
36
|
+
to_xml.xpath(".//t:Contact", NS).map do |node|
|
37
|
+
item_klass = Exchanger.const_get(node.name)
|
38
|
+
item_klass.new_from_xml(node)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Exchanger
|
2
|
+
# The UpdateItem operation is used to modify the properties of an existing item in the Exchanger store.
|
3
|
+
#
|
4
|
+
# http://msdn.microsoft.com/en-us/library/aa581084.aspx
|
5
|
+
# http://msdn.microsoft.com/en-us/library/aa579673.aspx
|
6
|
+
class UpdateItem < Operation
|
7
|
+
class Request < Operation::Request
|
8
|
+
attr_accessor :items
|
9
|
+
|
10
|
+
# Reset request options to defaults.
|
11
|
+
def reset
|
12
|
+
@items = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_xml
|
16
|
+
Nokogiri::XML::Builder.new do |xml|
|
17
|
+
xml.send("soap:Envelope", "xmlns:soap" => NS["soap"], "xmlns:t" => NS["t"], "xmlns:xsi" => NS["xsi"], "xmlns:xsd" => NS["xsd"]) do
|
18
|
+
xml.send("soap:Body") do
|
19
|
+
xml.UpdateItem("xmlns" => NS["m"], "ConflictResolution" => "AlwaysOverwrite") do
|
20
|
+
xml.ItemChanges do
|
21
|
+
items.each do |item|
|
22
|
+
item_change = item.to_xml_change
|
23
|
+
item_change.add_namespace_definition("t", NS["t"])
|
24
|
+
item_change.namespace = item_change.namespace_definitions[0]
|
25
|
+
xml << item_change.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Response < Operation::Response
|
36
|
+
def item_ids
|
37
|
+
to_xml.xpath(".//t:ItemId", NS).map do |node|
|
38
|
+
Identifier.new_from_xml(node)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Exchanger
|
2
|
+
module Persistence
|
3
|
+
def new_record?
|
4
|
+
not id
|
5
|
+
end
|
6
|
+
|
7
|
+
def save
|
8
|
+
if new_record?
|
9
|
+
create
|
10
|
+
else
|
11
|
+
update
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Reloads the +Element+ attributes from Exchanger.
|
16
|
+
def reload
|
17
|
+
if new_record?
|
18
|
+
false
|
19
|
+
else
|
20
|
+
reloaded_element = self.class.find(self.id)
|
21
|
+
@attributes = reloaded_element.attributes
|
22
|
+
reset_modifications
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "spec/spec_helper"
|
2
|
+
|
3
|
+
describe Exchanger::CalendarFolder do
|
4
|
+
before do
|
5
|
+
@folder = Exchanger::Folder.find(:calendar, "edgars.beigarts@tieto.com")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return calendar folder" do
|
9
|
+
@folder.class.should == Exchanger::CalendarFolder
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have calendar items" do
|
13
|
+
@folder.items.size.should > 0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Exchanger::CalendarItem do
|
18
|
+
before do
|
19
|
+
@folder = Exchanger::Folder.find(:calendar, "edgars.beigarts@tieto.com")
|
20
|
+
@item = @folder.items.first
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have start time" do
|
24
|
+
@item.start.class.should == Time
|
25
|
+
end
|
26
|
+
end
|