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.
@@ -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/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.gem
2
2
  .bundle
3
+ Gemfile.lock
3
4
  pkg/*
4
5
  tags
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 2.1.0
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
@@ -0,0 +1,121 @@
1
+ ## Cloudprint [![Build Status](https://travis-ci.org/minciue/cloudprint.png?branch=master)](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
@@ -5,4 +5,6 @@ Rake::TestTask.new(:test) do |test|
5
5
  test.libs << 'lib' << 'test'
6
6
  test.pattern = 'test/*_test.rb'
7
7
  test.verbose = true
8
- end
8
+ end
9
+
10
+ task :default => [:test]
@@ -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.5.2'
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'
@@ -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 " + CloudPrint.access_token
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
@@ -0,0 +1,6 @@
1
+ module CloudPrint
2
+
3
+ class RequestError < StandardError
4
+ end
5
+
6
+ end
@@ -1,51 +1,57 @@
1
1
  module CloudPrint
2
2
  class PrintJob
3
- attr_reader :id, :status, :error_code
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
- def self.find(jobid)
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
- def refresh!
17
- job = self.class.find_by_id(id)
18
- @status = job['status']
19
- @error_code = job['errorCode']
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 queued?
24
- status == "QUEUED"
13
+ def initialize(client, data)
14
+ @client = client
15
+ @data = data
25
16
  end
26
17
 
27
- def in_progress?
28
- status == "IN_PROGRESS"
29
- end
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
- private
44
-
45
- def self.find_by_id(id)
46
- response = CloudPrint.connection.get('/jobs') || {}
47
- return nil unless response['jobs'].is_a?(Array)
48
- response['jobs'].select{ |job| job['id'] == id }.first
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