gdata 0.0.1

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,102 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'cgi'
16
+
17
+ module GData
18
+ module Auth
19
+
20
+ # This class implements ClientLogin signatures for Data API requests.
21
+ # It can be used with a GData::Client::GData object.
22
+ class ClientLogin
23
+
24
+ DEFAULT_OPTIONS = {
25
+ :auth_url => 'https://www.google.com/accounts/ClientLogin',
26
+ :account_type => 'HOSTED_OR_GOOGLE' }
27
+
28
+ # The ClientLogin authentication handler
29
+ attr_accessor :auth_url
30
+ # One of 'HOSTED_OR_GOOGLE', 'GOOGLE', or 'HOSTED'.
31
+ # See documentation here:
32
+ # http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
33
+ attr_accessor :account_type
34
+ # The access token
35
+ attr_accessor :token
36
+ # The service name for the API you are working with
37
+ attr_accessor :service
38
+
39
+ # Initialize the class with the service name of an API that you wish
40
+ # to request a token for.
41
+ def initialize(service, options = {})
42
+ if service.nil?
43
+ raise ArgumentError, "Service name cannot be nil"
44
+ end
45
+
46
+ @service = service
47
+
48
+ options = DEFAULT_OPTIONS.merge(options)
49
+ options.each do |key, value|
50
+ self.send("#{key}=", value)
51
+ end
52
+ end
53
+
54
+ # Retrieves a token for the given username and password.
55
+ # source identifies your application.
56
+ # login_token and login_captcha are used only if you are responding
57
+ # to a previously issued CAPTCHA challenge.
58
+ def get_token(username, password, source, login_token = nil,
59
+ login_captcha = nil)
60
+ source = CGI.escape(source)
61
+ password = CGI.escape(password)
62
+ username = CGI.escape(username)
63
+ body = "accountType=#{@account_type}&Email=#{username}" +
64
+ "&Passwd=#{password}&service=#{@service}&source=#{source}"
65
+ if login_token and login_captcha
66
+ body += "&logintoken=#{login_token}&logincaptcha=#{login_captcha}"
67
+ end
68
+
69
+ request = GData::HTTP::Request.new(@auth_url, :body => body,
70
+ :method => :post)
71
+ service = GData::HTTP::DefaultService.new
72
+ response = service.make_request(request)
73
+ if response.status_code != 200
74
+ url = response.body[/Url=(.*)/,1]
75
+ error = response.body[/Error=(.*)/,1]
76
+
77
+ if error == "CaptchaRequired"
78
+ captcha_token = response.body[/CaptchaToken=(.*)/,1]
79
+ captcha_url = response.body[/CaptchaUrl=(.*)/,1]
80
+ raise GData::Client::CaptchaError.new(captcha_token, captcha_url),
81
+ "#{error} : #{url}"
82
+ end
83
+
84
+ raise GData::Client::AuthorizationError, "#{error} : #{url}"
85
+ end
86
+
87
+ @token = response.body[/Auth=(.*)/,1]
88
+ return @token
89
+ end
90
+
91
+ # Creates an appropriate Authorization header on a GData::HTTP::Request
92
+ # object.
93
+ def sign_request!(request)
94
+ if @token == nil
95
+ raise RuntimeError, "Cannot sign request without credentials"
96
+ end
97
+
98
+ request.headers['Authorization'] = "GoogleLogin auth=#{@token}"
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'gdata/client/gdata'
16
+ require 'gdata/client/youtube'
17
+
18
+ module GData
19
+ module Client
20
+ class AuthorizationError < RuntimeError
21
+ end
22
+
23
+ class BadRequestError < RuntimeError
24
+ end
25
+
26
+ # An error caused by ClientLogin issuing a CAPTCHA error.
27
+ class CaptchaError < RuntimeError
28
+ # The token identifying the CAPTCHA
29
+ attr_reader :token
30
+ # The URL to the CAPTCHA image
31
+ attr_reader :url
32
+
33
+ def initialize(token, url)
34
+ @token = token
35
+ @url = url
36
+ end
37
+ end
38
+
39
+ class ServerError < RuntimeError
40
+ end
41
+
42
+ class UnknownError < RuntimeError
43
+ end
44
+
45
+ class VersionConflictError < RuntimeError
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,165 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "rexml/document"
16
+
17
+ module GData
18
+ module Client
19
+
20
+ # A client object used to interact with different Google Data APIs.
21
+ class Base
22
+
23
+ DEFAULT_OPTIONS = {
24
+ :auth_handler => nil,
25
+ :http_service => GData::HTTP::DefaultService,
26
+ :version => "2",
27
+ :clientlogin_url => nil,
28
+ :clientlogin_service => nil,
29
+ :authsub_scope => nil,
30
+ :headers => {},
31
+ :source => 'AnonymousApp' }
32
+
33
+ # A subclass of GData::Auth that handles authentication signing.
34
+ attr_accessor :auth_handler
35
+ # A subclass of GData::HTTP that handles making HTTP requests.
36
+ attr_accessor :http_service
37
+ # Headers to include in every request.
38
+ attr_accessor :headers
39
+ # The API version being used.
40
+ attr_accessor :version
41
+ # The default URL for ClientLogin.
42
+ attr_accessor :clientlogin_url
43
+ # A default service name for ClientLogin (overriden by subclasses).
44
+ attr_accessor :clientlogin_service
45
+ # The broadest AuthSub scope for working with an API.
46
+ # This is overriden by the service-specific subclasses.
47
+ attr_accessor :authsub_scope
48
+ # A short string identifying the current application.
49
+ attr_accessor :source
50
+
51
+ def initialize(options = {})
52
+ options = DEFAULT_OPTIONS.merge(options)
53
+ options.each do |key, value|
54
+ self.send("#{key}=", value)
55
+ end
56
+ end
57
+
58
+ # Sends an HTTP request and parses the result with REXML.
59
+ def make_request(method, url, body = '')
60
+ headers = self.prepare_headers
61
+ request = GData::HTTP::Request.new(url, :headers => headers,
62
+ :method => method, :body => body)
63
+
64
+ if @auth_handler and @auth_handler.respond_to?(:sign_request!)
65
+ @auth_handler.sign_request!(request)
66
+ end
67
+
68
+ service = http_service.new
69
+ response = service.make_request(request)
70
+
71
+ case response.status_code
72
+ when 200, 201
73
+ #Do nothing, it's a success.
74
+ when 401, 403
75
+ raise AuthorizationError, response.body
76
+ when 400
77
+ raise BadRequestError, response.body
78
+ when 409
79
+ raise VersionConflictError, response.body
80
+ when 500
81
+ raise ServerError, response.body
82
+ else
83
+ raise UnknownError, response.status_code + ' ' + response.body
84
+ end
85
+
86
+ if response.body
87
+ begin
88
+ document = REXML::Document.new(response.body).root
89
+ if document.nil?
90
+ return response.body
91
+ else
92
+ return document
93
+ end
94
+ rescue
95
+ return response.body
96
+ end
97
+ end
98
+ end
99
+
100
+ # Performs an HTTP GET against the API.
101
+ def get(url)
102
+ return self.make_request(:get, url)
103
+ end
104
+
105
+ # Performs an HTTP PUT against the API.
106
+ def put(url, body)
107
+ return self.make_request(:put, url, body)
108
+ end
109
+
110
+ # Performs an HTTP POST against the API.
111
+ def post(url, body)
112
+ return self.make_request(:post, url, body)
113
+ end
114
+
115
+ # Performs an HTTP DELETE against the API.
116
+ def delete(url)
117
+ return self.make_request(:delete, url)
118
+ end
119
+
120
+ # Constructs some necessary headers for every request.
121
+ def prepare_headers
122
+ headers = @headers
123
+ headers['GData-Version'] = @version
124
+ headers['User-Agent'] = GData::Auth::SOURCE_LIB_STRING + @source
125
+ headers['Content-Type'] = 'application/atom+xml'
126
+ return headers
127
+ end
128
+
129
+ # Performs ClientLogin for the service.
130
+ def clientlogin(username, password, captcha_token = nil, captcha_answer = nil, service = nil)
131
+ if service.nil?
132
+ service = @clientlogin_service
133
+ end
134
+ @auth_handler = GData::Auth::ClientLogin.new(service)
135
+ if @clientlogin_url
136
+ @auth_handler.auth_url = @clientlogin_url
137
+ end
138
+ source = GData::Auth::SOURCE_LIB_STRING + @source
139
+ @auth_handler.get_token(username, password, source, captcha_token, captcha_answer)
140
+ end
141
+
142
+ def authsub_url(next_url, secure = false, session = true, domain = nil,
143
+ scope = nil)
144
+ if scope.nil?
145
+ scope = @authsub_scope
146
+ end
147
+ GData::Auth::AuthSub.get_url(next_url, scope, secure, session, domain)
148
+ end
149
+
150
+ # Sets an AuthSub token for the service.
151
+ def authsub_token=(token)
152
+ @auth_handler = GData::Auth::AuthSub.new(token)
153
+ end
154
+
155
+ # Sets a private key to use with AuthSub requests.
156
+ def authsub_private_key=(key)
157
+ if @auth_handler.class == GData::Auth::AuthSub
158
+ @auth_handler.private_key = key
159
+ else
160
+ raise RuntimeError, "An AuthSub token must be set first."
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module GData
16
+ module Client
17
+
18
+ # Client class to wrap working with the YouTube API. Sets some
19
+ # YouTube-specific options.
20
+ class YouTube < Base
21
+
22
+ DEFAULT_OPTIONS = {
23
+ :version => '2',
24
+ :clientlogin_url => 'https://www.google.com/youtube/accounts/ClientLogin',
25
+ :clientlogin_service => 'youtube',
26
+ :authsub_scope => 'http://gdata.youtube.com' }
27
+
28
+ # The YouTube developer key being used.
29
+ attr_accessor :developer_key
30
+ # The YouTube ClientID being used.
31
+ attr_accessor :client_id
32
+
33
+ def initialize(options = {})
34
+ options = DEFAULT_OPTIONS.merge(options)
35
+ super(options)
36
+ end
37
+
38
+ def prepare_headers
39
+ if @client_id
40
+ @headers['X-GData-Client'] = @client_id
41
+ end
42
+ if @developer_key
43
+ @headers['X-GData-Key'] = "key=#{@developer_key}"
44
+ end
45
+ super
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'gdata/http/default_service'
16
+ require 'gdata/http/request'
17
+ require 'gdata/http/response'
@@ -0,0 +1,64 @@
1
+ # Copyright (C) 2008 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'net/http'
16
+ require 'net/https'
17
+ require 'uri'
18
+
19
+ module GData
20
+ module HTTP
21
+
22
+ # This is the default implementation of the HTTP layer that uses
23
+ # Net::HTTP. You could roll your own if you have different requirements
24
+ # or cannot use Net::HTTP for some reason.
25
+ class DefaultService
26
+
27
+ # Take a GData::HTTP::Request, execute the request, and return a
28
+ # GData::HTTP::Response object.
29
+ def make_request(request)
30
+ url = URI.parse(request.url)
31
+ http = Net::HTTP.new(url.host, url.port)
32
+ http.use_ssl = (url.scheme == 'https')
33
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
34
+
35
+ case request.method
36
+ when :get
37
+ req = Net::HTTP::Get.new(url.request_uri)
38
+ when :put
39
+ req = Net::HTTP::Put.new(url.request_uri)
40
+ request.calculate_length!
41
+ when :post
42
+ req = Net::HTTP::Post.new(url.request_uri)
43
+ request.calculate_length!
44
+ when :delete
45
+ req = Net::HTTP::Delete.new(url.request_uri)
46
+ else
47
+ raise ArgumentError, "Unsupported HTTP method specified."
48
+ end
49
+
50
+ req.body = request.body
51
+ request.headers.each do |key, value|
52
+ req[key] = value
53
+ end
54
+ res = http.request(req)
55
+
56
+ response = Response.new
57
+ response.body = res.body
58
+ response.headers = res.header.to_hash
59
+ response.status_code = res.code.to_i
60
+ return response
61
+ end
62
+ end
63
+ end
64
+ end