gdata 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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