interfax 0.1.3 → 0.2.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.
- data/README.markdown +64 -4
- data/VERSION +1 -1
- data/lib/interfax/incoming.rb +204 -0
- data/lib/interfax.rb +2 -1
- data/spec/incoming_helper.rb +11 -0
- data/spec/incoming_spec.rb +107 -0
- data/spec/interfax_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +9 -8
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.
|
4
|
-
|
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
|
-
|
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
|
-
|
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
|
+
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
@@ -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
|
+
|
data/spec/interfax_spec.rb
CHANGED
@@ -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
|
-
|
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
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
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
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-
|
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
|