cloudprint 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.
- checksums.yaml +15 -0
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/README.md +121 -0
- data/Rakefile +3 -1
- data/cloudprint.gemspec +2 -2
- data/lib/cloudprint.rb +4 -71
- data/lib/cloudprint/client.rb +48 -0
- data/lib/cloudprint/connection.rb +7 -3
- data/lib/cloudprint/exceptions.rb +6 -0
- data/lib/cloudprint/print_job.rb +44 -38
- data/lib/cloudprint/print_job_collection.rb +39 -0
- data/lib/cloudprint/printer.rb +15 -19
- data/lib/cloudprint/printer_collection.rb +52 -0
- data/lib/cloudprint/version.rb +1 -1
- data/test/cloudprint_test.rb +47 -51
- data/test/connection_test.rb +2 -2
- data/test/helper.rb +7 -3
- data/test/print_job_test.rb +65 -13
- data/test/printer_test.rb +82 -17
- metadata +17 -33
- data/Gemfile.lock +0 -38
- data/README.rdoc +0 -19
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MmNiYTc0NGUzMGVmMTI1ZDAxYmNlMjE1NjhmNDg2OWY2MWU5ZWJjNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmY2YmVjM2JlOGMwNTA4Y2YxNTM5ZTY2Y2U2ZGVkZjIyYWE2MmE1Mg==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZWM3YjZjN2E3YjQ5MzZjNzM3ZTMwZTYwNzkxYzEyODRiN2QxZjYxYWVkYmY4
|
10
|
+
NjUxMGQ2MzYxMGY0NTQyYzlmYWIxMTUxMmU0YzYwZDQwYWZjOGY4NmIyMDBm
|
11
|
+
OWJiYTU1YWM0YTI4NmMwYTczMDg5ZDk1MGUyZjAyM2ExNWFjYTE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YjJjMmFmMDVlN2U1OTRkNWRmN2E3ODIwZTA0ZTY3NWVhYmFjNGQxOGVjMjY4
|
14
|
+
MjBmZTc1NTk4ZDQ2Yzg0MjE4ZTU2NGJmMmM5ZWZiOTAwMGIwZDFhZGVhMTNh
|
15
|
+
ZDg1MGM2ODczZDUyZGQxYjQ0YTZlMTNjNDU1NDZjYzI5ZmY3Nzg=
|
data/.travis.yml
ADDED
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
## Cloudprint [](https://travis-ci.org/minciue/cloudprint)
|
2
|
+
|
3
|
+
Cloudprint is a Ruby library for interacting with Google's Cloud Print service,
|
4
|
+
a technology that allows you to print over the web from anywhere to any
|
5
|
+
printer.
|
6
|
+
|
7
|
+
### Setting things up.
|
8
|
+
To start using cloudprint, you first need to add it to your Gemfile, with an
|
9
|
+
entry such as this.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'cloudprint'
|
13
|
+
```
|
14
|
+
|
15
|
+
Afterwards, run
|
16
|
+
```
|
17
|
+
bundle
|
18
|
+
```
|
19
|
+
|
20
|
+
Next, you'll need to authenticate your users with Google Cloud Print. Cloud
|
21
|
+
Print uses OAuth2 as an authentication mechanism.
|
22
|
+
|
23
|
+
First, you need to register your application within the Google Console. To do
|
24
|
+
that, go to [https://cloud.google.com/console](https://cloud.google.com/console)
|
25
|
+
. Doing this will provide you with two things that will be needed to manage
|
26
|
+
your users' printers: a client ID and a client secret.
|
27
|
+
|
28
|
+
### Authenticating your users.
|
29
|
+
Once you've registered your application, you will need to send your users to a
|
30
|
+
URL where they can allow your application to manage their printer.
|
31
|
+
|
32
|
+
Details on how such a URL can be built can be found here:
|
33
|
+
[https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl](https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl)
|
34
|
+
|
35
|
+
Eventually, the cloudprint gem will generate these URLs for you, but for now
|
36
|
+
you're on your own. Sorry about that.
|
37
|
+
|
38
|
+
Your users will be asked to sign into their Google Account and to enable your
|
39
|
+
app to manage their printer. Later on, they can then set up their printer from
|
40
|
+
the Google Cloud Print interface.
|
41
|
+
|
42
|
+
Once users authorize your application, they will be sent back to a URL you
|
43
|
+
specify which will have an extra parameter named 'code' attached to it.
|
44
|
+
You then exchange this code for a refresh token.
|
45
|
+
Instructions on how to get a refresh token can be found here:
|
46
|
+
[https://developers.google.com/accounts/docs/OAuth2WebServer#handlingtheresponse](https://developers.google.com/accounts/docs/OAuth2WebServer#handlingtheresponse)
|
47
|
+
|
48
|
+
With this in place (and with the user's printer set up from the CloudPrint UI)
|
49
|
+
you now have everything you need to send print jobs to this printer.
|
50
|
+
|
51
|
+
### Printing
|
52
|
+
First, you need to initialize a client with the data you just got from the
|
53
|
+
user. You will use this client object to interact with CloudPrint on behalf
|
54
|
+
of the user.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
client = CloudPrint::Client.new(
|
58
|
+
refresh_token: 'refresh_token',
|
59
|
+
client_id: 'client_id',
|
60
|
+
client_secret: 'client_secret',
|
61
|
+
callback_url: 'callback_url'
|
62
|
+
)
|
63
|
+
```
|
64
|
+
|
65
|
+
Printing with the cloudprint gem is done with two kinds of objects.
|
66
|
+
`CloudPrint::Printer`
|
67
|
+
objects represent printers your users have set up in their CloudPrint accounts.
|
68
|
+
You then ask these objects to print things like this:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
# Get a list of all the printers this client can talk to.
|
72
|
+
printers = client.printers.all
|
73
|
+
|
74
|
+
# Get a printer with a specific id
|
75
|
+
my_printer = client.printers.find('printer_id')
|
76
|
+
|
77
|
+
# Print using this printer.
|
78
|
+
# The :content option can also take a File object as a parameter.
|
79
|
+
# CloudPrint accepts HTML and PDF files.
|
80
|
+
my_printer.print(content: "<h1>Hello World</h1>", content_type: "text/html")
|
81
|
+
```
|
82
|
+
|
83
|
+
Here's where the second kind of object comes in. If your content has been
|
84
|
+
succesfully sent to the printer, the cloudprint gem will return a
|
85
|
+
`CloudPrint::PrintJob` object. Among other things, this object will provide you
|
86
|
+
with an ID for the print job and, a status code, and an error code if anything
|
87
|
+
happened that prevented your document from getting printed.
|
88
|
+
|
89
|
+
Most of the time, the PrintJob object that your print() call will return has a
|
90
|
+
status of `IN_PROGRESS` or `QUEUED`.
|
91
|
+
|
92
|
+
If your application can simply wait for the job, you can call refresh! on your
|
93
|
+
print job until its status changes. If not, you can store the ID and fetch the
|
94
|
+
print job at a later time to verify its status.
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
my_job = client.print_jobs.find('job_id')
|
98
|
+
|
99
|
+
# Returns the status, one of QUEUED, IN_PROGRESS, DONE, ERROR, SUBMITTED
|
100
|
+
my_job.status
|
101
|
+
```
|
102
|
+
|
103
|
+
You can also delete a job, after it has finished.
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
my_job.delete!
|
107
|
+
```
|
108
|
+
|
109
|
+
### Testing
|
110
|
+
For your testing needs, cloudprint objects can be stubbed at will and
|
111
|
+
initializing them does not require a connection. For example, to stub a print()
|
112
|
+
call with the shoulda library, one would do this:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
my_printer = CloudPrint::Printer.new(id: 'id', status: 'OK', name: 'test_printer', display_name: 'Test Printer'
|
116
|
+
my_job = CloudPrint::PrintJob.new({}) # see the PrintJob class for what this hash can hold
|
117
|
+
my_printer.stubs(:print).returns(my_job)
|
118
|
+
```
|
119
|
+
|
120
|
+
### More help
|
121
|
+
Please submit an issue via GitHub if you need more help with the cloudprint gem.
|
data/Rakefile
CHANGED
data/cloudprint.gemspec
CHANGED
@@ -15,10 +15,10 @@ This library provides a ruby-esque interface to Google Cloud Print.
|
|
15
15
|
cloudprint is a work in progress. I'll be adding documentation once all the basic GCP functionality is supported."
|
16
16
|
DESC
|
17
17
|
|
18
|
-
s.add_dependency 'oauth2', '~> 0.
|
18
|
+
s.add_dependency 'oauth2', '~> 0.8.0'
|
19
19
|
s.add_dependency 'json'
|
20
20
|
|
21
|
-
s.add_development_dependency 'mocha'
|
21
|
+
s.add_development_dependency 'mocha', '~> 0.10.0'
|
22
22
|
s.add_development_dependency 'rake'
|
23
23
|
s.add_development_dependency 'shoulda-context'
|
24
24
|
s.add_development_dependency 'test-unit'
|
data/lib/cloudprint.rb
CHANGED
@@ -4,77 +4,10 @@ require "oauth2"
|
|
4
4
|
require "json"
|
5
5
|
|
6
6
|
require "cloudprint/version"
|
7
|
+
require "cloudprint/client"
|
8
|
+
require "cloudprint/printer_collection"
|
7
9
|
require "cloudprint/printer"
|
8
10
|
require "cloudprint/connection"
|
11
|
+
require "cloudprint/print_job_collection"
|
9
12
|
require "cloudprint/print_job"
|
10
|
-
|
11
|
-
|
12
|
-
module CloudPrint
|
13
|
-
def self.setup(options = {})
|
14
|
-
@refresh_token = options[:refresh_token]
|
15
|
-
@client_id = options[:client_id]
|
16
|
-
@client_secret = options[:client_secret]
|
17
|
-
@callback_url = options[:callback_url]
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.client_secret
|
21
|
-
@client_secret
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.client_id
|
25
|
-
@client_id
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.refresh_token
|
29
|
-
@refresh_token
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.callback_url
|
33
|
-
@callback_url
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.connection
|
37
|
-
@connection ||= Connection.new
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
|
-
def self.access_token
|
42
|
-
if access_token_valid?
|
43
|
-
get_existing_access_token.token
|
44
|
-
else
|
45
|
-
get_new_access_token.token
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.refresh_token=(new_token)
|
50
|
-
@refresh_token = new_token
|
51
|
-
get_new_access_token
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def self.access_token_valid?
|
57
|
-
get_existing_access_token != nil && get_existing_access_token.token && get_existing_access_token.token.strip != "" && !get_existing_access_token.expired?
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.get_existing_access_token
|
61
|
-
@oauth2_access_token
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.get_new_access_token
|
65
|
-
@oauth2_access_token = new_oauth2_access_token
|
66
|
-
@oauth2_access_token
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.oauth_client
|
70
|
-
@oauth_client ||= OAuth2::Client.new(CloudPrint.client_id, CloudPrint.client_secret,
|
71
|
-
:authorize_url => "/o/oauth2/auth",
|
72
|
-
:token_url => "/o/oauth2/token",
|
73
|
-
:access_token_url => "/o/oauth2/token",
|
74
|
-
:site => 'https://accounts.google.com/')
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.new_oauth2_access_token
|
78
|
-
OAuth2::AccessToken.new(oauth_client, "", :refresh_token => CloudPrint.refresh_token).refresh!
|
79
|
-
end
|
80
|
-
end
|
13
|
+
require "cloudprint/exceptions"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module CloudPrint
|
2
|
+
class Client
|
3
|
+
attr_reader :client_secret
|
4
|
+
attr_reader :client_id
|
5
|
+
attr_reader :refresh_token
|
6
|
+
attr_reader :callback_url
|
7
|
+
attr_reader :connection
|
8
|
+
attr_reader :printers
|
9
|
+
attr_reader :print_jobs
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@refresh_token = options[:refresh_token]
|
13
|
+
@client_id = options[:client_id]
|
14
|
+
@client_secret = options[:client_secret]
|
15
|
+
@callback_url = options[:callback_url]
|
16
|
+
@connection = Connection.new(self)
|
17
|
+
@printers = PrinterCollection.new(self)
|
18
|
+
@print_jobs = PrintJobCollection.new(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_token
|
22
|
+
(access_token_valid? && @access_token || renew_access_token!).token
|
23
|
+
end
|
24
|
+
|
25
|
+
def refresh_token=(new_token)
|
26
|
+
@refresh_token = new_token
|
27
|
+
renew_access_token!
|
28
|
+
end
|
29
|
+
|
30
|
+
def access_token_valid?
|
31
|
+
@access_token.is_a?(OAuth2::AccessToken) && !@access_token.token.to_s.strip.empty? && !@access_token.expired?
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def renew_access_token!
|
37
|
+
@access_token = OAuth2::AccessToken.new(oauth_client, "", :refresh_token => refresh_token).refresh!
|
38
|
+
end
|
39
|
+
|
40
|
+
def oauth_client
|
41
|
+
@oauth_client ||= OAuth2::Client.new(client_id, client_secret,
|
42
|
+
:authorize_url => "/o/oauth2/auth",
|
43
|
+
:token_url => "/o/oauth2/token",
|
44
|
+
:access_token_url => "/o/oauth2/token",
|
45
|
+
:site => 'https://accounts.google.com/')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -2,9 +2,13 @@ require 'ostruct'
|
|
2
2
|
require "net/https"
|
3
3
|
require "uri"
|
4
4
|
|
5
|
-
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
6
5
|
module CloudPrint
|
7
6
|
class Connection
|
7
|
+
|
8
|
+
def initialize client
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
8
12
|
def get(path, params = {})
|
9
13
|
response = request(:get, path, params)
|
10
14
|
parse_response(response)
|
@@ -68,7 +72,7 @@ module CloudPrint
|
|
68
72
|
end
|
69
73
|
|
70
74
|
def set_request_headers(request)
|
71
|
-
request['Authorization'] = "OAuth " +
|
75
|
+
request['Authorization'] = "OAuth " + @client.access_token
|
72
76
|
request['X-CloudPrint-Proxy'] = 'api-prober'
|
73
77
|
end
|
74
78
|
|
@@ -92,4 +96,4 @@ module CloudPrint
|
|
92
96
|
"https://www.google.com/cloudprint" + path
|
93
97
|
end
|
94
98
|
end
|
95
|
-
end
|
99
|
+
end
|
data/lib/cloudprint/print_job.rb
CHANGED
@@ -1,51 +1,57 @@
|
|
1
1
|
module CloudPrint
|
2
2
|
class PrintJob
|
3
|
-
|
4
|
-
def initialize(options = {})
|
5
|
-
@id = options[:id]
|
6
|
-
@status = options[:status]
|
7
|
-
@error_code = options[:error_code]
|
8
|
-
end
|
3
|
+
STATUSES = %w{QUEUED IN_PROGRESS DONE ERROR SUBMITTED}
|
9
4
|
|
10
|
-
|
11
|
-
job = find_by_id(jobid)
|
12
|
-
return nil if job.nil?
|
13
|
-
self.new(:id => job['id'], :status => job['status'], :error_code => job['errorCode'])
|
14
|
-
end
|
5
|
+
attr_reader :client
|
15
6
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
self
|
7
|
+
class << self
|
8
|
+
def new_from_response client, response_hash
|
9
|
+
new client, Util.normalize_response_data(response_hash)
|
10
|
+
end
|
21
11
|
end
|
22
12
|
|
23
|
-
def
|
24
|
-
|
13
|
+
def initialize(client, data)
|
14
|
+
@client = client
|
15
|
+
@data = data
|
25
16
|
end
|
26
17
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def done?
|
32
|
-
status == "DONE"
|
33
|
-
end
|
34
|
-
|
35
|
-
def error?
|
36
|
-
status == "ERROR"
|
37
|
-
end
|
38
|
-
|
39
|
-
def submitted?
|
40
|
-
status == "SUBMITTED"
|
18
|
+
def refresh!
|
19
|
+
@data = Util.normalize_response_data(client.print_jobs.find_by_id(id))
|
20
|
+
self
|
41
21
|
end
|
42
22
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
23
|
+
def delete!
|
24
|
+
response = client.connection.get('/deletejob', { :jobid => id })
|
25
|
+
response['success'] || raise(RequestError, response['message'])
|
26
|
+
end
|
27
|
+
|
28
|
+
def method_missing(meth, *args, &block)
|
29
|
+
if @data.has_key?(meth)
|
30
|
+
@data[meth]
|
31
|
+
elsif STATUSES.map{ |s| s.downcase + '?' }.include?(meth.to_s)
|
32
|
+
@data[:status].downcase == meth.to_s.chop
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Util
|
39
|
+
def self.normalize_response_data(response_hash)
|
40
|
+
{
|
41
|
+
:id => response_hash['id'],
|
42
|
+
:status => response_hash['status'],
|
43
|
+
:error_code => response_hash['errorCode'],
|
44
|
+
:printer_id => response_hash['printerid'],
|
45
|
+
:title => response_hash['title'],
|
46
|
+
:content_type => response_hash['contentType'],
|
47
|
+
:file_url => response_hash['fileUrl'],
|
48
|
+
:ticket_url => response_hash['ticketUrl'],
|
49
|
+
:create_time => Time.at(response_hash['createTime'].to_f / 1000),
|
50
|
+
:update_time => Time.at(response_hash['updateTime'].to_f / 1000),
|
51
|
+
:message => response_hash['message'],
|
52
|
+
:tags => response_hash['tags']
|
53
|
+
}
|
54
|
+
end
|
49
55
|
end
|
50
56
|
end
|
51
57
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CloudPrint
|
2
|
+
class PrintJobCollection
|
3
|
+
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize client
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def find(jobid)
|
11
|
+
job = find_by_id(jobid)
|
12
|
+
return nil if job.nil?
|
13
|
+
new_from_response job
|
14
|
+
end
|
15
|
+
|
16
|
+
def all
|
17
|
+
fetch_jobs.map { |j| new_from_response j }
|
18
|
+
end
|
19
|
+
|
20
|
+
def new data
|
21
|
+
PrintJob.new client, data
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_from_response response
|
25
|
+
PrintJob.new_from_response client, response
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def find_by_id(id)
|
31
|
+
fetch_jobs.select{ |job| job['id'] == id }.first
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_jobs
|
35
|
+
response = client.connection.get('/jobs') || {}
|
36
|
+
response['jobs'] || []
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|