interfax 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,7 +1,12 @@
1
1
  # Interfax/Ruby
2
2
 
3
- This library is a wrapper for the interfax.net fax service. Until now only sending of html faxes and status
4
- querying is supported.
3
+ This library is a wrapper for the interfax.net fax service. For now,
4
+ you can do the following:
5
+
6
+ * Send HTML faxes
7
+ * Query the status of a sent fax
8
+ * Retrieve a list of incoming faxes
9
+ * Get the image for a sent fax
5
10
 
6
11
  If you're willing to help, just drop me a line.
7
12
 
@@ -11,6 +16,8 @@ If you're willing to help, just drop me a line.
11
16
 
12
17
  ## Usage
13
18
 
19
+ ### Outgoing Faxes
20
+
14
21
  Create a class, inherit from Interfax::Base and set authentication parameters:
15
22
 
16
23
  class OrderFax < Interfax::Base
@@ -19,7 +26,7 @@ Create a class, inherit from Interfax::Base and set authentication parameters:
19
26
  end
20
27
 
21
28
 
22
- ### Sending
29
+ #### Sending Faxes
23
30
 
24
31
  Creating a fax:
25
32
 
@@ -37,7 +44,7 @@ Finally:
37
44
 
38
45
  result_id = fax.deliver
39
46
 
40
- ### Querying
47
+ #### Getting Sent Faxes
41
48
 
42
49
  To get all faxes:
43
50
 
@@ -55,6 +62,59 @@ or get more than one at once:
55
62
 
56
63
  OrderFax.find(123456789,234567890)
57
64
 
65
+
66
+ ### Incoming Faxes
67
+
68
+
69
+ #### Getting Incoming Faxes
70
+
71
+ To get a list of incoming faxes, you can either use the base class:
72
+
73
+ Interfax::Incoming.username = 'my_interfax_username'
74
+ Interfax::Incoming.password = 'my_interfax_password'
75
+ Interfax::Incoming.limit = 15 # optional, default 100
76
+ Interfax::Incoming.mark_as_read = false # optional, default false
77
+
78
+ # fetch unread incoming faxes
79
+ faxes = Interfax::Incoming.new
80
+
81
+ If you want you can define your own subclass -- useful for keeping
82
+ authentication info handy -- you can do so:
83
+
84
+ class IncomingFaxes < Interfax::Incoming
85
+ self.username = 'my_interfax_username'
86
+ self.password = 'my_interfax_password'
87
+ end
88
+
89
+ # fetch all incoming faxes
90
+ faxes = Interfax::Incoming.all
91
+
92
+ There are four methods for fetching incoming faxes:
93
+
94
+ #all - Fetch all incoming faxes
95
+ #unread - Fetch unread incoming faxes
96
+ #account_all - Fetch incoming faxes for all users on your account
97
+ #account_unread - Fetch unread incoming faxes for all users on your account
98
+
99
+ The account_ methods require that you have admin privileges. For more
100
+ information, see the Interfax API documentation.
101
+
102
+
103
+ #### Getting Incoming Fax Images
104
+
105
+ The Interfax::Incoming methods described above return an array of
106
+ instances of the class you called it on. If you're using the
107
+ Interfax::Incoming class you'll get those. If you use a subclass,
108
+ we'll instantiate that class and return an array of those.
109
+
110
+ In either event, call the `#image` method to fetch the PDF/TIF of the
111
+ fax as a string, suitable for writing to the filesystem in the normal fashion.
112
+
113
+ # Assume you've defined a sublcass as above
114
+ all_faxes = IncomingFaxes.all
115
+ all_faxes[0].image # return the first fax's image
116
+
117
+
58
118
  ## Interfax API documentation
59
119
 
60
120
  http://www.interfax.net/en/dev/webservice/reference/methods
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
@@ -0,0 +1,204 @@
1
+ require 'soap/wsdlDriver'
2
+ require 'Base64'
3
+
4
+ module Interfax
5
+
6
+ # = Interfax::Incoming
7
+ #
8
+ # Allows interaction with the Interfax Inbound API, documented at:
9
+ # http://www.interfax.net/en/dev/webservice/reference_in
10
+ #
11
+ # == Retrieving incoming faxes
12
+ #
13
+ # Set the +username+ and +password+ variables appropriately, and
14
+ # then call one of the query methods, which are described in further
15
+ # detail below.
16
+ #
17
+ # Interfax::Incoming.username = 'my_interfax_username'
18
+ # Interfax::Incoming.password = 'my_interfax_password'
19
+ # faxes = Interfax::Incoming.unread
20
+ #
21
+ # You can extend Interfax::Incoming, and the query methdos will
22
+ # return instances of your subclass. This is useful for extending
23
+ # functionality, or consolidating your configuration in one place.
24
+ #
25
+ # class InboundFax < Interfax::Incoming
26
+ # self.username = 'my_interfax_username'
27
+ # self.password = 'my_interfax_password'
28
+ #
29
+ # def write_image_to_file
30
+ # File.open("/path/to/file", 'w') { |f| f.write(image)
31
+ # end
32
+ # end
33
+ #
34
+ # faxes = InboundFax.all # this is an array of InboundFax objects
35
+ # faxes.map(&:write_image_to_file)
36
+ #
37
+ # == Methods
38
+ #
39
+ # The methods available for fetching or querying inbound faxes are:
40
+ #
41
+ # * +#all+ - Retrieves all inbound faxes, up to +limit+.
42
+ # * +#unread+ - Retrieves any unread faxes, up to +limit+.
43
+ # * +#account_all+ - Retrieves inbound faxes for all users on your
44
+ # account, up to +limit+. Requires an administrator account.
45
+ # * +#account_unread+ - Same as above, but fetches only unread
46
+ # faxes. Also requires an administrator account.
47
+ #
48
+ # As seen above, these methods return instances of the class they're
49
+ # called on, which makes it easy to extend your objects for custom
50
+ # functionality.
51
+ #
52
+ # == Configuration
53
+ #
54
+ # We require that the following two configuration variables be set
55
+ # at the class level, as seen in the examples above.
56
+ #
57
+ # * +username+ - [required] Your interfax username.
58
+ # * +password+ - [requierd] Your interfax password.
59
+ #
60
+ # We also support a few other configuration methods, which are
61
+ # explained further in Interfax's API documentation.
62
+ #
63
+ # * +limit+ - [1..100, default 100] The maximum number of faxes to return.
64
+ # * +mark_as_read+ - [boolean, default false] Whether or not to mark
65
+ # retrieved faxes as sent.
66
+ #
67
+ # These options are also accepted as options when requesting faxes:
68
+ #
69
+ # # Assume username/password already set
70
+ # Interfax::Incoming.all(:limit => 10, :mark_as_read => true)
71
+ #
72
+ # Options supplied this way will temporarily override any options
73
+ # set on the class.
74
+
75
+ class Incoming
76
+
77
+ class << self
78
+ attr_accessor :username, :password, :mark_as_read, :limit #:nodoc:
79
+
80
+ def soap_client #:nodoc:
81
+ SOAP::WSDLDriverFactory.
82
+ new("https://ws.interfax.net/inbound.asmx?WSDL").
83
+ create_rpc_driver
84
+ end
85
+
86
+ def query(type, opts = {}) #:nodoc:
87
+ result = self.soap_client.GetList(:Username => self.username,
88
+ :Password => self.password,
89
+ :MaxItems => opts[:limit] || self.limit || 100,
90
+ :MarkAsRead => opts[:mark_as_read] || self.mark_as_read || false,
91
+ :LType => type
92
+ )
93
+
94
+ return [] if result.nil? || !defined?(result.objMessageItem)
95
+ [*result.objMessageItem.messageItem].map do |fax|
96
+ self.new(fax.messageID, fax.messageSize)
97
+ end
98
+ end
99
+
100
+ # Returns all inbound messages for your user up to the +limit+
101
+ # option. Optionally marks the faxes as read.
102
+ #
103
+ # ==== Options (as hash)
104
+ #
105
+ # Both of these will default to whatever values you've set for
106
+ # the class, or 100 (limit) or false (mark_as_read) if you haven't.
107
+ # * +:limit+ - Maximum number of faxes to return.
108
+ # * +:mark_as_read+: Mark fetched faxes as read.
109
+
110
+ def all(opts = {})
111
+ query('AllMessages', opts)
112
+ end
113
+
114
+ # Returns any unread messages for your user up to the +limit+
115
+ # option. Optionally marks the faxes as read.
116
+ #
117
+ # ==== Options (as hash)
118
+ #
119
+ # Both of these will default to whatever values you've set for
120
+ # the class, or 100 (limit) or false (mark_as_read) if you haven't.
121
+ # * +:limit+ - Maximum number of faxes to return.
122
+ # * +:mark_as_read+: Mark fetched faxes as read.
123
+
124
+ def unread(opts = {})
125
+ query('NewMessages', opts)
126
+ end
127
+
128
+ # Returns all messages for all users on your account, up
129
+ # to the +limit+ option. Optionally marks the faxes as
130
+ # read. Requires your user be an administrator for your account.
131
+ #
132
+ # ==== Options (as hash)
133
+ #
134
+ # Both of these will default to whatever values you've set for
135
+ # the class, or 100 (limit) or false (mark_as_read) if you haven't.
136
+ # * +:limit+ - Maximum number of faxes to return.
137
+ # * +:mark_as_read+: Mark fetched faxes as read.
138
+
139
+ def account_all(opts = {})
140
+ query('AccountAllMessages', opts)
141
+ end
142
+
143
+ # Returns any unread messages for all users on your account, up
144
+ # to the +limit+ option. Optionally marks the faxes as
145
+ # read. Requires your user be an administrator for your account.
146
+ #
147
+ # ==== Options (as hash)
148
+ #
149
+ # Both of these will default to whatever values you've set for
150
+ # the class, or 100 (limit) or false (mark_as_read) if you haven't.
151
+ # * +:limit+ - Maximum number of faxes to return.
152
+ # * +:mark_as_read+: Mark fetched faxes as read.
153
+
154
+ def account_unread(opts = {})
155
+ query('AccountNewMessages', opts)
156
+ end
157
+
158
+ end
159
+
160
+
161
+
162
+ attr_accessor :username, :password, :mark_as_read, :chunk_size, :message_id, :message_size, :image #:nodoc:
163
+
164
+ def initialize(message_id, message_size)
165
+ @username = self.class.username
166
+ @password = self.class.password
167
+ @mark_as_read = self.class.mark_as_read || false
168
+ @chunk_size = 100000
169
+ @message_id = message_id
170
+ @message_size = message_size.to_i
171
+ @image = nil
172
+ end
173
+
174
+ # Retrieves the image from the Interfax Inbound API, as a
175
+ # string. Suitable for writing to a file or streaming to a client.
176
+ def image
177
+ @image || fetch_image
178
+ end
179
+
180
+ def fetch_image #:nodoc:
181
+ @image = ""
182
+ downloaded_size = 0
183
+ while downloaded_size < @message_size
184
+ result = self.class.soap_client.GetImageChunk(:Username => @username,
185
+ :Password => @password,
186
+ :MessageID => @message_id,
187
+ :MarkAsRead => @mark_as_read,
188
+ :ChunkSize => @chunk_size,
189
+ :From => downloaded_size)
190
+
191
+ # TODO: Make this throw a nicer exception on failure
192
+ if defined?(result.image)
193
+ @image << Base64.decode64(result.image)
194
+ end
195
+ downloaded_size += @chunk_size
196
+
197
+ end
198
+
199
+ @image
200
+ end
201
+
202
+ end
203
+
204
+ end
data/lib/interfax.rb CHANGED
@@ -5,4 +5,5 @@ $:.unshift(File.dirname(__FILE__)) unless
5
5
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
6
6
 
7
7
  require 'interfax/fax_item'
8
- require 'interfax/base'
8
+ require 'interfax/base'
9
+ require 'interfax/incoming'
@@ -0,0 +1,11 @@
1
+ module IncomingHelper
2
+
3
+ class MockInterfaxResponse < Struct.new(:objMessageItem); end
4
+ class ObjMessageItem < Struct.new(:messageItem); end
5
+ class MessageItem < Struct.new(:messageID, :messageSize); end
6
+
7
+
8
+ def mock_getlist_response(count = 1)
9
+ MockInterfaxResponse.new(ObjMessageItem.new([MessageItem.new('messageid', '200000')] * count))
10
+ end
11
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+ include IncomingHelper
3
+
4
+ describe Interfax::Incoming do
5
+
6
+ before(:each) do
7
+ @client_mock = mock("SoapClient",
8
+ :GetList => true,
9
+ :GetImageChunk => true)
10
+
11
+ Interfax::Incoming.stub!(:soap_client).and_return(@client_mock)
12
+ end
13
+
14
+ context "querying for incoming faxes" do
15
+
16
+ it "should query for all messages" do
17
+ Interfax::Incoming.should_receive(:query).with('AllMessages', anything())
18
+ Interfax::Incoming.all
19
+ end
20
+
21
+ it "should query for unread messages" do
22
+ Interfax::Incoming.should_receive(:query).with('NewMessages', anything())
23
+ Interfax::Incoming.unread
24
+ end
25
+
26
+ it "should query for all users' unread messages" do
27
+ Interfax::Incoming.should_receive(:query).with('AccountNewMessages', anything())
28
+ Interfax::Incoming.account_unread
29
+ end
30
+
31
+ it "should query for all users' messages" do
32
+ Interfax::Incoming.should_receive(:query).with('AccountAllMessages', anything())
33
+ Interfax::Incoming.account_all
34
+ end
35
+
36
+ it "should respect the :limit argument over a class-defined limit" do
37
+ @client_mock.should_receive(:GetList).with(hash_including(:MaxItems => 24))
38
+ Interfax::Incoming.limit = 50
39
+ Interfax::Incoming.all(:limit => 24)
40
+ end
41
+
42
+ it "should use the class-specified limit over the default" do
43
+ @client_mock.should_receive(:GetList).with(hash_including(:MaxItems => 50))
44
+ Interfax::Incoming.limit = 50
45
+ Interfax::Incoming.all
46
+ end
47
+
48
+ it "should respect the :mark_as_read argument over the class-defined value" do
49
+ @client_mock.should_receive(:GetList).with(hash_including(:MarkAsRead => true))
50
+ Interfax::Incoming.mark_as_read = false
51
+ Interfax::Incoming.all(:mark_as_read => true)
52
+ end
53
+
54
+ it "should use the class-specified mark_as_read over the default" do
55
+ @client_mock.should_receive(:GetList).with(hash_including(:MarkAsRead => true))
56
+ Interfax::Incoming.mark_as_read = true
57
+ Interfax::Incoming.all
58
+ end
59
+
60
+
61
+ it "should return instances of the base class when called on the base class" do
62
+ @client_mock.stub!(:GetList).and_return(mock_getlist_response)
63
+ Interfax::Incoming.all[0].class.should == Interfax::Incoming
64
+ end
65
+
66
+ it "should return instances of the subclass when called on a subclass" do
67
+ class TestFax < Interfax::Incoming; end
68
+
69
+ @client_mock.
70
+ stub!(:GetList).
71
+ and_return(mock_getlist_response)
72
+ TestFax.stub!(:soap_client).and_return(@client_mock)
73
+
74
+ TestFax.all[0].class.should == TestFax
75
+ end
76
+
77
+ end
78
+
79
+ context "fetching images" do
80
+
81
+ before(:each) do
82
+ @fax = Interfax::Incoming.new('message_id', '200000')
83
+ end
84
+
85
+ it "should fetch the image when asked" do
86
+ @client_mock.should_receive(:GetImageChunk).at_least(:once)
87
+ @fax.image
88
+ end
89
+
90
+ it "should cache the image once received" do
91
+ @client_mock.should_receive(:GetImageChunk).at_least(:once)
92
+ @fax.image
93
+ @client_mock.should_not_receive(:GetImageChunk)
94
+ @fax.image
95
+ end
96
+
97
+ it "should respect the class-defined mark_as_read option" do
98
+ Interfax::Incoming.mark_as_read = true
99
+ @client_mock.should_receive(:GetImageChunk).with(hash_including(:MarkAsRead => true))
100
+ @fax.image
101
+ end
102
+
103
+
104
+ end
105
+
106
+ end
107
+
@@ -2,6 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "Interfax" do
4
4
  it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
5
+ pending "hey buddy, you should probably rename this file and start specing for real"
6
6
  end
7
7
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'interfax'
4
4
  require 'spec'
5
5
  require 'spec/autorun'
6
+ require 'incoming_helper'
6
7
 
7
8
  Spec::Runner.configure do |config|
8
9
 
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interfax
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 1
9
- - 3
10
- version: 0.1.3
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Sascha Brink
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-01-20 00:00:00 +01:00
17
+ date: 2011-04-28 00:00:00 +02:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 13
30
28
  segments:
31
29
  - 1
32
30
  - 2
@@ -51,6 +49,9 @@ files:
51
49
  - lib/interfax.rb
52
50
  - lib/interfax/base.rb
53
51
  - lib/interfax/fax_item.rb
52
+ - lib/interfax/incoming.rb
53
+ - spec/incoming_helper.rb
54
+ - spec/incoming_spec.rb
54
55
  - spec/interfax_spec.rb
55
56
  - spec/spec.opts
56
57
  - spec/spec_helper.rb
@@ -68,7 +69,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
69
  requirements:
69
70
  - - ">="
70
71
  - !ruby/object:Gem::Version
71
- hash: 3
72
72
  segments:
73
73
  - 0
74
74
  version: "0"
@@ -77,7 +77,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
- hash: 3
81
80
  segments:
82
81
  - 0
83
82
  version: "0"
@@ -89,5 +88,7 @@ signing_key:
89
88
  specification_version: 3
90
89
  summary: A ruby wrapper for the interfax webservice (SOAP)
91
90
  test_files:
91
+ - spec/incoming_helper.rb
92
+ - spec/incoming_spec.rb
92
93
  - spec/interfax_spec.rb
93
94
  - spec/spec_helper.rb