├── .gitignore ├── test ├── testimage.jpg ├── test_config.yml.example ├── ts_gdata_http.rb ├── ts_gdata_auth.rb ├── ts_gdata_client.rb ├── tc_gdata_http_request.rb ├── tc_gdata_client_base.rb ├── test_helper.rb ├── tc_gdata_client_calendar.rb ├── ts_gdata.rb ├── tc_gdata_http_mime_body.rb ├── tc_gdata_auth_authsub.rb ├── tc_gdata_auth_clientlogin.rb ├── tc_gdata_client_photos.rb └── tc_gdata_client_youtube.rb ├── lib ├── gdata │ ├── http.rb │ ├── auth.rb │ ├── client │ │ ├── apps.rb │ │ ├── blogger.rb │ │ ├── contacts.rb │ │ ├── gbase.rb │ │ ├── health.rb │ │ ├── finance.rb │ │ ├── gmail.rb │ │ ├── notebook.rb │ │ ├── doclist.rb │ │ ├── booksearch.rb │ │ ├── spreadsheets.rb │ │ ├── webmaster_tools.rb │ │ ├── photos.rb │ │ ├── youtube.rb │ │ ├── calendar.rb │ │ └── base.rb │ ├── http │ │ ├── response.rb │ │ ├── request.rb │ │ ├── default_service.rb │ │ └── mime_body.rb │ ├── client.rb │ └── auth │ │ ├── clientlogin.rb │ │ └── authsub.rb └── gdata.rb ├── Rakefile ├── gdata.gemspec ├── README └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | test/test_config.yml 2 | -------------------------------------------------------------------------------- /test/testimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DV/gdata/master/test/testimage.jpg -------------------------------------------------------------------------------- /test/test_config.yml.example: -------------------------------------------------------------------------------- 1 | --- 2 | username: myaccount 3 | password: mypassword 4 | # uncomment to test authsub 5 | #authsub_token: someauthsubtoken 6 | # uncomment to test secure authsub 7 | #authsub_private_key: /path/to/private/key 8 | -------------------------------------------------------------------------------- /lib/gdata/http.rb: -------------------------------------------------------------------------------- 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/mime_body' 17 | require 'gdata/http/request' 18 | require 'gdata/http/response' 19 | -------------------------------------------------------------------------------- /lib/gdata/auth.rb: -------------------------------------------------------------------------------- 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/auth/clientlogin' 16 | require 'gdata/auth/authsub' 17 | 18 | module GData 19 | module Auth 20 | SOURCE_LIB_STRING = 'GoogleDataRubyUtil-' 21 | end 22 | end -------------------------------------------------------------------------------- /lib/gdata.rb: -------------------------------------------------------------------------------- 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 | $:.unshift(File.dirname(__FILE__)) 16 | 17 | require 'gdata/http' 18 | require 'gdata/client' 19 | require 'gdata/auth' 20 | # This is for Unicode "support" 21 | if RUBY_VERSION < '1.9' 22 | require 'jcode' 23 | $KCODE = 'UTF8' 24 | end 25 | -------------------------------------------------------------------------------- /lib/gdata/client/apps.rb: -------------------------------------------------------------------------------- 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 Apps Provisioning API. 19 | class Apps < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'apps' 23 | super(options) 24 | end 25 | end 26 | end 27 | end -------------------------------------------------------------------------------- /test/ts_gdata_http.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | require 'tc_gdata_http_request' 17 | require 'tc_gdata_http_mime_body' 18 | 19 | class TS_GData_HTTP 20 | def self.suite 21 | suite = Test::Unit::TestSuite.new 22 | suite << TC_GData_HTTP_Request.suite 23 | suite << TC_GData_HTTP_MimeBody.suite 24 | return suite 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /test/ts_gdata_auth.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | require 'tc_gdata_auth_clientlogin' 17 | require 'tc_gdata_auth_authsub' 18 | 19 | class TS_GData_Auth 20 | def self.suite 21 | suite = Test::Unit::TestSuite.new 22 | suite << TC_GData_Auth_ClientLogin.suite 23 | suite << TC_GData_Auth_AuthSub.suite 24 | return suite 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/gdata/client/blogger.rb: -------------------------------------------------------------------------------- 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 Blogger API. 19 | class Blogger < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'blogger' 23 | options[:authsub_scope] ||= 'http://www.blogger.com/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/contacts.rb: -------------------------------------------------------------------------------- 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 Contacts API. 19 | class Contacts < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'cp' 23 | options[:authsub_scope] ||= 'http://www.google.com/m8/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/gbase.rb: -------------------------------------------------------------------------------- 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 Google Base API. 19 | class GBase < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'gbase' 23 | options[:authsub_scope] ||= 'http://www.google.com/base/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/health.rb: -------------------------------------------------------------------------------- 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 Health API. 19 | class Health < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'health' 23 | options[:authsub_scope] ||= 'https://www.google.com/health/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/finance.rb: -------------------------------------------------------------------------------- 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 Finance API. 19 | class Finance < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'finance' 23 | options[:authsub_scope] ||= 'http://finance.google.com/finance/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/gmail.rb: -------------------------------------------------------------------------------- 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 GMail Atom Feed. 19 | class GMail < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'mail' 23 | options[:authsub_scope] ||= 'https://mail.google.com/mail/feed/atom/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/notebook.rb: -------------------------------------------------------------------------------- 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 Notebook Data API. 19 | class Notebook < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'notebook' 23 | options[:authsub_scope] ||= 'http://www.google.com/notebook/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/doclist.rb: -------------------------------------------------------------------------------- 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 Documents List Data API. 19 | class DocList < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'writely' 23 | options[:authsub_scope] ||= 'http://docs.google.com/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/booksearch.rb: -------------------------------------------------------------------------------- 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 Book Search Data API. 19 | class BookSearch < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'print' 23 | options[:authsub_scope] ||= 'http://www.google.com/books/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/spreadsheets.rb: -------------------------------------------------------------------------------- 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 Spreadsheets API. 19 | class Spreadsheets < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'wise' 23 | options[:authsub_scope] ||= 'http://spreadsheets.google.com/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/webmaster_tools.rb: -------------------------------------------------------------------------------- 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 Webmaster Tools API. 19 | class WebmasterTools < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'sitemaps' 23 | options[:authsub_scope] ||= 'http://www.google.com/webmasters/tools/feeds/' 24 | super(options) 25 | end 26 | end 27 | end 28 | end -------------------------------------------------------------------------------- /lib/gdata/client/photos.rb: -------------------------------------------------------------------------------- 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 Picasa Web Albums API. 19 | class Photos < Base 20 | 21 | def initialize(options = {}) 22 | options[:clientlogin_service] ||= 'lh2' 23 | options[:authsub_scope] ||= 'http://picasaweb.google.com/data/' 24 | options[:version] ||= '1' 25 | super(options) 26 | end 27 | end 28 | end 29 | end -------------------------------------------------------------------------------- /test/ts_gdata_client.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | require 'tc_gdata_client_base' 17 | require 'tc_gdata_client_calendar' 18 | require 'tc_gdata_client_photos' 19 | require 'tc_gdata_client_youtube' 20 | 21 | class TS_GData_Client 22 | def self.suite 23 | suite = Test::Unit::TestSuite.new 24 | suite << TC_GData_Client_Base.suite 25 | suite << TC_GData_Client_Calendar.suite 26 | suite << TC_GData_Client_Photos.suite 27 | suite << TC_GData_Client_YouTube.suite 28 | return suite 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test/tc_gdata_http_request.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_HTTP_Request < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def test_world_is_sane 24 | assert(true, 'World is not sane.') 25 | end 26 | 27 | def test_google_is_live 28 | request = GData::HTTP::Request.new('http://www.google.com') 29 | 30 | service = GData::HTTP::DefaultService.new 31 | 32 | response = service.make_request(request) 33 | 34 | assert_equal(200, response.status_code) 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /lib/gdata/http/response.rb: -------------------------------------------------------------------------------- 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' 16 | 17 | module GData 18 | module HTTP 19 | 20 | # An extremely simple class to hold the values of an HTTP response. 21 | class Response 22 | 23 | # The HTTP response code. 24 | attr_accessor :status_code 25 | # The body of the HTTP response. 26 | attr_accessor :body 27 | # The headers of the HTTP response. 28 | attr_accessor :headers 29 | 30 | # Converts the response body into a REXML::Document 31 | def to_xml 32 | if @body 33 | begin 34 | return REXML::Document.new(@body).root 35 | rescue 36 | raise GData::Client::Error, "Response body not XML." 37 | end 38 | else 39 | return nil 40 | end 41 | end 42 | end 43 | end 44 | end -------------------------------------------------------------------------------- /test/tc_gdata_client_base.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_Client_Base < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def test_simple_gdata_get 24 | service = GData::Client::Base.new 25 | feed = service.get('http://gdata.youtube.com/feeds/base/videos?max-results=1').to_xml 26 | assert_not_nil(feed, 'feed can not be nil') 27 | end 28 | 29 | def test_clientlogin_with_service 30 | service = GData::Client::Base.new 31 | service.clientlogin(self.get_username(), self.get_password(), nil, nil, 32 | 'youtube') 33 | feed = service.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1').to_xml 34 | assert_not_nil(feed, 'feed can not be nil') 35 | end 36 | 37 | end 38 | 39 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | require 'yaml' 17 | require 'test/unit' 18 | require 'test/unit/ui/console/testrunner' 19 | 20 | $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') 21 | require 'gdata' 22 | 23 | module TestHelper 24 | 25 | def get_config() 26 | if not defined?(@config_file) 27 | @config_file = YAML::load_file(File.join(File.dirname(__FILE__), 'test_config.yml')) 28 | end 29 | return @config_file 30 | end 31 | 32 | def get_username() 33 | return self.get_config()['username'] 34 | end 35 | 36 | def get_password() 37 | return self.get_config()['password'] 38 | end 39 | 40 | def get_authsub_token() 41 | return self.get_config()['authsub_token'] 42 | end 43 | 44 | def get_authsub_private_key() 45 | return self.get_config()['authsub_private_key'] 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /test/tc_gdata_client_calendar.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_Client_Calendar < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def setup 24 | @cl = GData::Client::Calendar.new 25 | @cl.clientlogin(self.get_username, self.get_password) 26 | end 27 | 28 | def test_get_all_calendars 29 | response = @cl.get('http://www.google.com/calendar/feeds/default/allcalendars/full') 30 | self.assert_equal(200, response.status_code, 'Must not be a redirect.') 31 | self.assert_not_nil(@cl.session_cookie, 'Must have a session cookie.') 32 | feed = response.to_xml 33 | self.assert_not_nil(feed, 'feed can not be nil') 34 | 35 | #login again to make sure the session cookie gets cleared 36 | @cl.clientlogin(self.get_username, self.get_password) 37 | self.assert_nil(@cl.session_cookie, 'Should clear session cookie.') 38 | end 39 | 40 | 41 | end 42 | -------------------------------------------------------------------------------- /test/ts_gdata.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | require 'ts_gdata_http' 19 | require 'ts_gdata_client' 20 | require 'ts_gdata_auth' 21 | 22 | class TS_GData 23 | def self.suite 24 | suite = Test::Unit::TestSuite.new("GData Test Suite") 25 | suite << UnicodeStringTest.suite 26 | suite << TS_GData_HTTP.suite 27 | suite << TS_GData_Client.suite 28 | suite << TS_GData_Auth.suite 29 | return suite 30 | end 31 | end 32 | 33 | class UnicodeStringTest < Test::Unit::TestCase 34 | if RUBY_VERSION < '1.9' 35 | def test_jlength 36 | s = "Καλημέρα κόσμε!" 37 | assert_equal(15, s.jlength) # Note the 'j' 38 | assert_not_equal(15, s.length) # Normal, non unicode length 39 | assert_equal(28, s.length) # Greek letters happen to take two-bytes 40 | end 41 | else 42 | def test_length 43 | s = "Καλημέρα κόσμε!" 44 | assert_equal(15, s.length) # Note the 'j' 45 | end 46 | end 47 | end 48 | 49 | 50 | Test::Unit::UI::Console::TestRunner.run(TS_GData) 51 | -------------------------------------------------------------------------------- /lib/gdata/client/youtube.rb: -------------------------------------------------------------------------------- 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 | # The YouTube developer key being used. 23 | attr_accessor :developer_key 24 | # The YouTube ClientID being used. 25 | attr_accessor :client_id 26 | 27 | def initialize(options = {}) 28 | options[:clientlogin_service] ||= 'youtube' 29 | options[:clientlogin_url] ||= 'https://www.google.com/youtube/accounts/ClientLogin' 30 | options[:authsub_scope] ||= 'http://gdata.youtube.com' 31 | options[:version] ||= '2' 32 | super(options) 33 | end 34 | 35 | # Custom prepare_headers to include the developer key and clientID 36 | def prepare_headers 37 | if @client_id 38 | @headers['X-GData-Client'] = @client_id 39 | end 40 | if @developer_key 41 | @headers['X-GData-Key'] = "key=#{@developer_key}" 42 | end 43 | super 44 | end 45 | end 46 | end 47 | end -------------------------------------------------------------------------------- /test/tc_gdata_http_mime_body.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_HTTP_MimeBody < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def test_mime_body_string 24 | stream = GData::HTTP::MimeBodyString.new('testing 1 2 3') 25 | 26 | self.assert_equal('t', stream.read(1)) 27 | self.assert_equal('esting', stream.read(6)) 28 | self.assert_equal(' 1 2 ', stream.read(5)) 29 | self.assert_equal('3', stream.read(50)) 30 | self.assert_equal(false, stream.read(10)) 31 | end 32 | 33 | def test_mime_body_string_large_read 34 | stream = GData::HTTP::MimeBodyString.new('test string') 35 | 36 | self.assert_equal('test string', stream.read(1024)) 37 | self.assert_equal(false, stream.read(1024)) 38 | end 39 | 40 | def test_mime_body_string_unicode 41 | stream = GData::HTTP::MimeBodyString.new('λ') 42 | self.assert(stream.read(1), 'Greek character should be two bytes') 43 | self.assert(stream.read(1), 'Greek character should be two full bytes') 44 | self.assert_equal(false, stream.read(1)) 45 | end 46 | 47 | end 48 | -------------------------------------------------------------------------------- /test/tc_gdata_auth_authsub.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_Auth_AuthSub < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def test_make_authenticated_request 24 | token = self.get_authsub_token() 25 | key = self.get_authsub_private_key() 26 | service = GData::Client::YouTube.new 27 | if token 28 | 29 | service.authsub_token = token 30 | if key 31 | service.authsub_private_key = key 32 | end 33 | 34 | feed = service.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1') 35 | self.assert_not_nil(feed, 'Feed should not be nil') 36 | end 37 | end 38 | 39 | def test_generate_url 40 | scope = 'http://gdata.youtube.com' 41 | next_url = 'http://example.com' 42 | secure = true 43 | session = false 44 | url = GData::Auth::AuthSub.get_url(next_url, scope, secure, session) 45 | self.assert_equal('https://www.google.com/accounts/AuthSubRequest?next=http%3A%2F%2Fexample.com&scope=http%3A%2F%2Fgdata.youtube.com&session=0&secure=1', url) 46 | 47 | # test generating with a pre-populated scope 48 | yt = GData::Client::YouTube.new 49 | client_url = yt.authsub_url(next_url, secure, session) 50 | self.assert_equal(url, client_url) 51 | 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 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 'rubygems' 16 | require 'rake/gempackagetask' 17 | require 'rake/rdoctask' 18 | require 'rake/testtask' 19 | 20 | task :default => [:test] 21 | 22 | desc 'Run tests' 23 | task :test do 24 | ruby "test/ts_gdata.rb" 25 | end 26 | 27 | desc 'generate RDoc documentation' 28 | task :doc do 29 | system "rdoc -U --title 'gdata module documentation' -m README README lib/" 30 | end 31 | 32 | desc 'create/update gemspec file' 33 | task :gemspec do 34 | spec = Gem::Specification.new do |s| 35 | s.platform = Gem::Platform::RUBY 36 | s.author = 'Jeff Fisher' 37 | s.email = 'jfisher@youtube.com' 38 | s.homepage = 'http://code.google.com/p/gdata-ruby-util' 39 | s.summary = "Google Data APIs Ruby Utility Library" 40 | s.rubyforge_project = 'gdata' 41 | s.name = 'gdata' 42 | s.version = '1.1.1' 43 | s.requirements << 'none' 44 | s.require_path = 'lib' 45 | s.test_files = FileList['test/ts_gdata.rb'] 46 | s.has_rdoc = true 47 | s.extra_rdoc_files = ['README', 'LICENSE'] 48 | s.rdoc_options << '--main' << 'README' 49 | s.files = FileList.new('[A-Z]*', 'lib/**/*.rb', 'test/**/*') do |fl| 50 | fl.exclude(/test_config\.yml$/) 51 | end 52 | s.description = < 0 41 | @session_cookie = response.headers['set-cookie'] 42 | return self.make_request(method, url, body, 43 | retries - 1) 44 | else 45 | return response 46 | end 47 | end 48 | 49 | # Custom prepare_headers to include the session cookie if it exists 50 | def prepare_headers 51 | if @session_cookie 52 | @headers['cookie'] = @session_cookie 53 | end 54 | super 55 | end 56 | end 57 | end 58 | end -------------------------------------------------------------------------------- /gdata.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |s| 4 | s.name = %q{gdata} 5 | s.version = "1.1.2" 6 | 7 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 8 | s.authors = ["Jeff Fisher"] 9 | s.date = %q{2009-09-10} 10 | s.description = %q{This gem provides a set of wrappers designed to make it easy to work with 11 | the Google Data APIs. 12 | } 13 | s.email = %q{jfisher@youtube.com} 14 | s.extra_rdoc_files = ["README", "LICENSE"] 15 | s.files = ["LICENSE", "Rakefile", "README", "lib/gdata/auth/authsub.rb", "lib/gdata/auth/clientlogin.rb", "lib/gdata/auth.rb", "lib/gdata/client/apps.rb", "lib/gdata/client/base.rb", "lib/gdata/client/blogger.rb", "lib/gdata/client/booksearch.rb", "lib/gdata/client/calendar.rb", "lib/gdata/client/contacts.rb", "lib/gdata/client/doclist.rb", "lib/gdata/client/finance.rb", "lib/gdata/client/gbase.rb", "lib/gdata/client/gmail.rb", "lib/gdata/client/health.rb", "lib/gdata/client/notebook.rb", "lib/gdata/client/photos.rb", "lib/gdata/client/spreadsheets.rb", "lib/gdata/client/webmaster_tools.rb", "lib/gdata/client/youtube.rb", "lib/gdata/client.rb", "lib/gdata/http/default_service.rb", "lib/gdata/http/mime_body.rb", "lib/gdata/http/request.rb", "lib/gdata/http/response.rb", "lib/gdata/http.rb", "lib/gdata.rb", "test/tc_gdata_auth_authsub.rb", "test/tc_gdata_auth_clientlogin.rb", "test/tc_gdata_client_base.rb", "test/tc_gdata_client_calendar.rb", "test/tc_gdata_client_photos.rb", "test/tc_gdata_client_youtube.rb", "test/tc_gdata_http_mime_body.rb", "test/tc_gdata_http_request.rb", "test/test_config.yml.example", "test/test_helper.rb", "test/testimage.jpg", "test/ts_gdata.rb", "test/ts_gdata_auth.rb", "test/ts_gdata_client.rb", "test/ts_gdata_http.rb"] 16 | s.homepage = %q{http://code.google.com/p/gdata-ruby-util} 17 | s.rdoc_options = ["--main", "README"] 18 | s.require_paths = ["lib"] 19 | s.requirements = ["none"] 20 | s.rubyforge_project = %q{gdata} 21 | s.rubygems_version = %q{1.3.5} 22 | s.summary = %q{Google Data APIs Ruby Utility Library} 23 | s.test_files = ["test/ts_gdata.rb"] 24 | 25 | if s.respond_to? :specification_version then 26 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION 27 | s.specification_version = 3 28 | 29 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then 30 | else 31 | end 32 | else 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/gdata/http/request.rb: -------------------------------------------------------------------------------- 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 HTTP 19 | 20 | # Very simple class to hold everything about an HTTP request. 21 | class Request 22 | 23 | # The URL of the request. 24 | attr_accessor :url 25 | # The body of the request. 26 | attr_accessor :body 27 | # The HTTP method being used in the request. 28 | attr_accessor :method 29 | # The HTTP headers of the request. 30 | attr_accessor :headers 31 | 32 | # Only the URL itself is required, everything else is optional. 33 | def initialize(url, options = {}) 34 | @url = url 35 | options.each do |key, value| 36 | self.send("#{key}=", value) 37 | end 38 | 39 | @method ||= :get 40 | @headers ||= {} 41 | end 42 | 43 | # Returns whether or not a request is chunked. 44 | def chunked? 45 | if @headers['Transfer-Encoding'] == 'chunked' 46 | return true 47 | else 48 | return false 49 | end 50 | end 51 | 52 | # Sets if the request is using chunked transfer-encoding. 53 | def chunked=(enabled) 54 | if enabled 55 | @headers['Transfer-Encoding'] = 'chunked' 56 | else 57 | @headers.delete('Transfer-Encoding') 58 | end 59 | end 60 | 61 | # Calculates and sets the length of the body. 62 | def calculate_length! 63 | if not @headers['Content-Length'] and not chunked? \ 64 | and method != :get and method != :delete 65 | if @body 66 | @headers['Content-Length'] = @body.length 67 | else 68 | @headers['Content-Length'] = 0 69 | end 70 | end 71 | end 72 | end 73 | end 74 | end -------------------------------------------------------------------------------- /test/tc_gdata_client_photos.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_Client_Photos < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def setup 24 | @gp = GData::Client::Photos.new 25 | @gp.source = 'Ruby Client Unit Tests' 26 | @gp.clientlogin(self.get_username(), self.get_password()) 27 | end 28 | 29 | def test_authenticated_dropbox_feed 30 | feed = @gp.get('http://picasaweb.google.com/data/feed/api/user/default/albumid/default?max-results=1').to_xml 31 | self.assert_not_nil(feed, 'feed can not be nil') 32 | end 33 | 34 | def test_photo_upload 35 | test_image = File.join(File.dirname(__FILE__), 'testimage.jpg') 36 | mime_type = 'image/jpeg' 37 | 38 | response = @gp.post_file('http://picasaweb.google.com/data/feed/api/user/default/albumid/default', 39 | test_image, mime_type).to_xml 40 | 41 | edit_uri = response.elements["link[@rel='edit']"].attributes['href'] 42 | 43 | @gp.delete(edit_uri) 44 | end 45 | 46 | def test_photo_upload_with_metadata 47 | test_image = File.join(File.dirname(__FILE__), 'testimage.jpg') 48 | mime_type = 'image/jpeg' 49 | 50 | entry = <<-EOF 51 | 52 | ruby-client-testing.jpg 53 | Test case for Ruby Client Library. 54 | 56 | 57 | EOF 58 | 59 | response = @gp.post_file('http://picasaweb.google.com/data/feed/api/user/default/albumid/default', 60 | test_image, mime_type, entry).to_xml 61 | 62 | edit_uri = response.elements["link[@rel='edit']"].attributes['href'] 63 | 64 | @gp.delete(edit_uri) 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/gdata/client.rb: -------------------------------------------------------------------------------- 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/base' 16 | require 'gdata/client/apps' 17 | require 'gdata/client/blogger' 18 | require 'gdata/client/booksearch' 19 | require 'gdata/client/calendar' 20 | require 'gdata/client/contacts' 21 | require 'gdata/client/doclist' 22 | require 'gdata/client/finance' 23 | require 'gdata/client/gbase' 24 | require 'gdata/client/gmail' 25 | require 'gdata/client/health' 26 | require 'gdata/client/notebook' 27 | require 'gdata/client/photos' 28 | require 'gdata/client/spreadsheets' 29 | require 'gdata/client/webmaster_tools' 30 | require 'gdata/client/youtube' 31 | 32 | module GData 33 | module Client 34 | 35 | # Base class for GData::Client errors 36 | class Error < RuntimeError 37 | end 38 | 39 | # Base class for errors raised due to requests 40 | class RequestError < Error 41 | 42 | # The Net::HTTPResponse that caused this error. 43 | attr_accessor :response 44 | 45 | # Creates a new RequestError from Net::HTTPResponse +response+ with a 46 | # message containing the error code and response body. 47 | def initialize(response) 48 | @response = response 49 | 50 | super "request error #{response.status_code}: #{response.body}" 51 | end 52 | 53 | end 54 | 55 | class AuthorizationError < RequestError 56 | end 57 | 58 | class BadRequestError < RequestError 59 | end 60 | 61 | # An error caused by ClientLogin issuing a CAPTCHA error. 62 | class CaptchaError < RuntimeError 63 | # The token identifying the CAPTCHA 64 | attr_reader :token 65 | # The URL to the CAPTCHA image 66 | attr_reader :url 67 | 68 | def initialize(token, url) 69 | @token = token 70 | @url = url 71 | end 72 | end 73 | 74 | class ServerError < RequestError 75 | end 76 | 77 | class UnknownError < RequestError 78 | end 79 | 80 | class VersionConflictError < RequestError 81 | end 82 | 83 | end 84 | end -------------------------------------------------------------------------------- /test/tc_gdata_client_youtube.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*-3 2 | # Copyright (C) 2008 Google Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | $:.unshift(File.dirname(__FILE__)) 17 | require 'test_helper' 18 | 19 | class TC_GData_Client_YouTube < Test::Unit::TestCase 20 | 21 | include TestHelper 22 | 23 | def setup 24 | @yt = GData::Client::YouTube.new 25 | self.assert(@yt.headers.empty?, 'headers should be empty.') 26 | @yt.clientlogin(self.get_username(), self.get_password()) 27 | @yt.client_id = 'ytapi-Google-GDataUnitTests-lcqr3u89-1' 28 | @yt.developer_key = 'AI39si4vwXwDLR5MrtsdR1ULUD8__EnEccla-0bnqV40KpeFDIyCwEv0VJqZKHUsO3MvVM_bXHp3cAr55HmMYMhqfxzLMUgDXA' 29 | end 30 | 31 | def test_authenticated_uploads_feed 32 | 33 | 34 | feed = @yt.get('http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1').to_xml 35 | self.assert_not_nil(feed, 'feed can not be nil') 36 | end 37 | 38 | def test_favorites 39 | 40 | video_id = 'zlfKdbWwruY' 41 | 42 | entry = <<-EOF 43 | 44 | #{video_id} 45 | 46 | EOF 47 | 48 | response = @yt.post('http://gdata.youtube.com/feeds/api/users/default/favorites', entry).to_xml 49 | 50 | edit_uri = response.elements["link[@rel='edit']"].attributes['href'] 51 | 52 | @yt.delete(edit_uri) 53 | 54 | end 55 | 56 | def test_playlist 57 | entry = <<-EOF 58 | 60 | Ruby Utility Unit Test 61 | This is a test playlist. 62 | 63 | EOF 64 | 65 | response = @yt.post('http://gdata.youtube.com/feeds/api/users/default/playlists', entry).to_xml 66 | 67 | edit_uri = response.elements["link[@rel='edit']"].attributes['href'] 68 | 69 | response.elements["summary"].text = "Updated description" 70 | 71 | response = @yt.put(edit_uri, response.to_s).to_xml 72 | 73 | self.assert_equal("Updated description", response.elements["summary"].text) 74 | 75 | @yt.delete(edit_uri) 76 | end 77 | 78 | end 79 | -------------------------------------------------------------------------------- /lib/gdata/http/default_service.rb: -------------------------------------------------------------------------------- 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 | when :post 41 | req = Net::HTTP::Post.new(url.request_uri) 42 | when :delete 43 | req = Net::HTTP::Delete.new(url.request_uri) 44 | else 45 | raise ArgumentError, "Unsupported HTTP method specified." 46 | end 47 | 48 | case request.body 49 | when String 50 | req.body = request.body 51 | when Hash 52 | req.set_form_data(request.body) 53 | when File 54 | req.body_stream = request.body 55 | request.chunked = true 56 | when GData::HTTP::MimeBody 57 | req.body_stream = request.body 58 | request.chunked = true 59 | else 60 | req.body = request.body.to_s 61 | end 62 | 63 | request.headers.each do |key, value| 64 | req[key] = value 65 | end 66 | 67 | request.calculate_length! 68 | 69 | res = http.request(req) 70 | 71 | response = Response.new 72 | response.body = res.body 73 | response.headers = Hash.new 74 | res.each do |key, value| 75 | response.headers[key] = value 76 | end 77 | response.status_code = res.code.to_i 78 | return response 79 | end 80 | end 81 | end 82 | end -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | = GData 2 | 3 | * http://code.google.com/p/gdata 4 | 5 | == DESCRIPTION: 6 | 7 | Ruby wrapper for working with Google Data APIs 8 | 9 | == SYNOPSIS: 10 | 11 | yt = GData::Client::YouTube.new 12 | yt.source = 'my_cool_application' 13 | yt.clientlogin('username', 'password') 14 | yt.client_id = 'CLIENT_ID' 15 | yt.developer_key = 'DEVELOPER_KEY' 16 | feed = yt.get('http://gdata.youtube.com/feeds/api/users/default/uploads').to_xml 17 | 18 | # creating, updating, and deleting a playlist 19 | 20 | entry = <<-EOF 21 | 23 | Ruby Utility Unit Test 24 | This is a test playlist. 25 | 26 | EOF 27 | 28 | response = yt.post('http://gdata.youtube.com/feeds/api/users/default/playlists', entry).to_xml 29 | 30 | edit_uri = response.elements["link[@rel='edit']"].attributes['href'] 31 | 32 | response.elements["summary"].text = "Updated description" 33 | 34 | response = yt.put(edit_uri, response.to_s).to_xml 35 | 36 | yt.delete(edit_uri).to_xml 37 | 38 | # uploading a video 39 | 40 | test_movie = '/path/to/a/movie.mov' 41 | mime_type = 'video/quicktime' 42 | feed = 'http://uploads.gdata.youtube.com/feeds/api/users/default/uploads' 43 | 44 | entry = < 48 | 49 | Test Movie 50 | 51 | This is a test with the Ruby library 52 | 53 | People 55 | 56 | test,lame 57 | 58 | 59 | EOF 60 | 61 | response = @yt.post_file(feed, test_movie, mime_type, entry).to_xml 62 | 63 | == REQUIREMENTS: 64 | 65 | * A sunny disposition 66 | 67 | Tested against Ruby 1.8.6 patch level 114 68 | 69 | == INSTALL: 70 | 71 | sudo gem install gdata 72 | 73 | To generate documentation: 74 | 75 | rake doc 76 | 77 | To run unit tests: 78 | 79 | cp test/test_config.yml.example test/test_config.yml 80 | # edit test/test_config.yml 81 | rake test 82 | 83 | == LICENSE: 84 | 85 | Copyright (C) 2008 Google Inc. 86 | 87 | Licensed under the Apache License, Version 2.0 (the "License"); 88 | you may not use this file except in compliance with the License. 89 | You may obtain a copy of the License at 90 | 91 | http://www.apache.org/licenses/LICENSE-2.0 92 | 93 | Unless required by applicable law or agreed to in writing, software 94 | distributed under the License is distributed on an "AS IS" BASIS, 95 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 96 | See the License for the specific language governing permissions and 97 | limitations under the License. -------------------------------------------------------------------------------- /lib/gdata/http/mime_body.rb: -------------------------------------------------------------------------------- 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 | 16 | module GData 17 | module HTTP 18 | 19 | # Class acts as a virtual file handle to a MIME multipart message body 20 | class MimeBody 21 | 22 | # The MIME boundary being used. 23 | attr_reader :boundary 24 | 25 | # All fields are required, the entry should be a string and is assumed 26 | # to be XML. 27 | def initialize(entry, file, file_mime_type) 28 | @boundary = "END_OF_PART_#{rand(64000)}" 29 | entry = wrap_entry(entry, file_mime_type) 30 | closing_boundary = MimeBodyString.new("\r\n--#{@boundary}--") 31 | @parts = [entry, file, closing_boundary] 32 | @current_part = 0 33 | end 34 | 35 | # Implement read so that this class can be treated as a stream. 36 | def read(bytes_requested) 37 | if @current_part >= @parts.length 38 | return false 39 | end 40 | 41 | buffer = @parts[@current_part].read(bytes_requested) 42 | 43 | until buffer.length == bytes_requested 44 | @current_part += 1 45 | next_buffer = self.read(bytes_requested - buffer.length) 46 | break if not next_buffer 47 | buffer += next_buffer 48 | end 49 | 50 | return buffer 51 | end 52 | 53 | # Returns the content type of the message including boundary. 54 | def content_type 55 | return "multipart/related; boundary=\"#{@boundary}\"" 56 | end 57 | 58 | private 59 | 60 | # Sandwiches the entry body into a MIME message 61 | def wrap_entry(entry, file_mime_type) 62 | wrapped_entry = "--#{@boundary}\r\n" 63 | wrapped_entry += "Content-Type: application/atom+xml\r\n\r\n" 64 | wrapped_entry += entry 65 | wrapped_entry += "--#{@boundary}\r\n" 66 | wrapped_entry += "Content-Type: #{file_mime_type}\r\n\r\n" 67 | return MimeBodyString.new(wrapped_entry) 68 | end 69 | 70 | end 71 | 72 | # Class makes a string into a stream-like object 73 | class MimeBodyString 74 | 75 | def initialize(source_string) 76 | @string = source_string 77 | @bytes_read = 0 78 | end 79 | 80 | # Implement read so that this class can be treated as a stream. 81 | def read(bytes_requested) 82 | if @bytes_read == @string.bytesize 83 | return false 84 | elsif bytes_requested > @string.bytesize - @bytes_read 85 | bytes_requested = @string.bytesize - @bytes_read 86 | end 87 | 88 | buffer = @string[@bytes_read, bytes_requested] 89 | @bytes_read += bytes_requested 90 | 91 | return buffer 92 | end 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /lib/gdata/auth/clientlogin.rb: -------------------------------------------------------------------------------- 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 | # The ClientLogin authentication handler 25 | attr_accessor :auth_url 26 | # One of 'HOSTED_OR_GOOGLE', 'GOOGLE', or 'HOSTED'. 27 | # See documentation here: 28 | # http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html 29 | attr_accessor :account_type 30 | # The access token 31 | attr_accessor :token 32 | # The service name for the API you are working with 33 | attr_accessor :service 34 | 35 | # Initialize the class with the service name of an API that you wish 36 | # to request a token for. 37 | def initialize(service, options = {}) 38 | if service.nil? 39 | raise ArgumentError, "Service name cannot be nil" 40 | end 41 | 42 | @service = service 43 | 44 | options.each do |key, value| 45 | self.send("#{key}=", value) 46 | end 47 | 48 | @auth_url ||= 'https://www.google.com/accounts/ClientLogin' 49 | @account_type ||= 'HOSTED_OR_GOOGLE' 50 | end 51 | 52 | # Retrieves a token for the given username and password. 53 | # source identifies your application. 54 | # login_token and login_captcha are used only if you are responding 55 | # to a previously issued CAPTCHA challenge. 56 | def get_token(username, password, source, login_token = nil, 57 | login_captcha = nil) 58 | body = Hash.new 59 | body['accountType'] = @account_type 60 | body['Email'] = username 61 | body['Passwd'] = password 62 | body['service'] = @service 63 | body['source'] = source 64 | if login_token and login_captcha 65 | body['logintoken'] = login_token 66 | body['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.new(response) 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 GData::Client::Error, "Cannot sign request without credentials" 96 | end 97 | 98 | request.headers['Authorization'] = "GoogleLogin auth=#{@token}" 99 | end 100 | end 101 | end 102 | end -------------------------------------------------------------------------------- /lib/gdata/auth/authsub.rb: -------------------------------------------------------------------------------- 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 | require 'openssl' 17 | require 'base64' 18 | 19 | module GData 20 | module Auth 21 | 22 | # This class implements AuthSub signatures for Data API requests. 23 | # It can be used with a GData::Client::GData object. 24 | class AuthSub 25 | 26 | # The URL of AuthSubRequest. 27 | REQUEST_HANDLER = 'https://www.google.com/accounts/AuthSubRequest' 28 | # The URL of AuthSubSessionToken. 29 | SESSION_HANDLER = 'https://www.google.com/accounts/AuthSubSessionToken' 30 | # The URL of AuthSubRevokeToken. 31 | REVOKE_HANDLER = 'https://www.google.com/accounts/AuthSubRevokeToken' 32 | # The URL of AuthSubInfo. 33 | INFO_HANDLER = 'https://www.google.com/accounts/AuthSubTokenInfo' 34 | # 2 ** 64, the largest 64 bit unsigned integer 35 | BIG_INT_MAX = 18446744073709551616 36 | 37 | # AuthSub access token. 38 | attr_accessor :token 39 | # Private RSA key used to sign secure requests. 40 | attr_reader :private_key 41 | 42 | # Initialize the class with a new token. Optionally pass a private 43 | # key or custom URLs. 44 | def initialize(token, options = {}) 45 | if token.nil? 46 | raise ArgumentError, "Token cannot be nil." 47 | elsif token.class != String 48 | raise ArgumentError, "Token must be a String." 49 | end 50 | 51 | @token = token 52 | 53 | options.each do |key, value| 54 | self.send("#{key}=", value) 55 | end 56 | end 57 | 58 | # Set the private key to use with this AuthSub token. 59 | # The key can be an OpenSSL::PKey::RSA object, a string containing a 60 | # private key in PEM format, or a string specifying a path to a PEM 61 | # file that contains the private key. 62 | def private_key=(key) 63 | begin 64 | if key.nil? or key.class == OpenSSL::PKey::RSA 65 | @private_key = key 66 | elsif File.exists?(key) 67 | key_from_file = File.read(key) 68 | @private_key = OpenSSL::PKey::RSA.new(key_from_file) 69 | else 70 | @private_key = OpenSSL::PKey::RSA.new(key) 71 | end 72 | rescue 73 | raise ArgumentError, "Not a valid private key." 74 | end 75 | end 76 | 77 | # Sign a GData::Http::Request object with a valid AuthSub Authorization 78 | # header. 79 | def sign_request!(request) 80 | header = "AuthSub token=\"#{@token}\"" 81 | 82 | if @private_key 83 | time = Time.now.to_i 84 | nonce = OpenSSL::BN.rand_range(BIG_INT_MAX) 85 | method = request.method.to_s.upcase 86 | data = "#{method} #{request.url} #{time} #{nonce}" 87 | sig = @private_key.sign(OpenSSL::Digest::SHA1.new, data) 88 | sig = Base64.encode64(sig).gsub(/\n/, '') 89 | header = "#{header} sigalg=\"rsa-sha1\" data=\"#{data}\"" 90 | header = "#{header} sig=\"#{sig}\"" 91 | end 92 | 93 | request.headers['Authorization'] = header 94 | end 95 | 96 | # Upgrade the current token into a session token. 97 | def upgrade 98 | request = GData::HTTP::Request.new(SESSION_HANDLER) 99 | sign_request!(request) 100 | service = GData::HTTP::DefaultService.new 101 | response = service.make_request(request) 102 | if response.status_code != 200 103 | raise GData::Client::AuthorizationError.new(response) 104 | end 105 | 106 | @token = response.body[/Token=(.*)/,1] 107 | return @token 108 | 109 | end 110 | 111 | # Return some information about the current token. If the current token 112 | # is a one-time use token, this operation will use it up! 113 | def info 114 | request = GData::HTTP::Request.new(INFO_HANDLER) 115 | sign_request!(request) 116 | service = GData::HTTP::DefaultService.new 117 | response = service.make_request(request) 118 | if response.status_code != 200 119 | raise GData::Client::AuthorizationError.new(response) 120 | end 121 | 122 | result = {} 123 | result[:target] = response.body[/Target=(.*)/,1] 124 | result[:scope] = response.body[/Scope=(.*)/,1] 125 | result[:secure] = response.body[/Secure=(.*)/,1] 126 | return result 127 | 128 | end 129 | 130 | # Revoke the token. 131 | def revoke 132 | request = GData::HTTP::Request.new(REVOKE_HANDLER) 133 | sign_request!(request) 134 | service = GData::HTTP::DefaultService.new 135 | response = service.make_request(request) 136 | if response.status_code != 200 137 | raise GData::Client::AuthorizationError.new(response) 138 | end 139 | 140 | end 141 | 142 | # Return the proper URL for an AuthSub approval page with the requested 143 | # scope. next_url should be a URL that points back to your code that 144 | # will receive the token. domain is optionally a Google Apps domain. 145 | def self.get_url(next_url, scope, secure = false, session = true, 146 | domain = nil) 147 | next_url = CGI.escape(next_url) 148 | scope = CGI.escape(scope) 149 | secure = secure ? 1 : 0 150 | session = session ? 1 : 0 151 | body = "next=#{next_url}&scope=#{scope}&session=#{session}" + 152 | "&secure=#{secure}" 153 | if domain 154 | domain = CGI.escape(domain) 155 | body = "#{body}&hd=#{domain}" 156 | end 157 | return "#{REQUEST_HANDLER}?#{body}" 158 | end 159 | end 160 | end 161 | end -------------------------------------------------------------------------------- /lib/gdata/client/base.rb: -------------------------------------------------------------------------------- 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 | # A client object used to interact with different Google Data APIs. 19 | class Base 20 | 21 | # A subclass of GData::Auth that handles authentication signing. 22 | attr_accessor :auth_handler 23 | # A subclass of GData::HTTP that handles making HTTP requests. 24 | attr_accessor :http_service 25 | # Headers to include in every request. 26 | attr_accessor :headers 27 | # The API version being used. 28 | attr_accessor :version 29 | # The default URL for ClientLogin. 30 | attr_accessor :clientlogin_url 31 | # A default service name for ClientLogin (overriden by subclasses). 32 | attr_accessor :clientlogin_service 33 | # The broadest AuthSub scope for working with an API. 34 | # This is overriden by the service-specific subclasses. 35 | attr_accessor :authsub_scope 36 | # A short string identifying the current application. 37 | attr_accessor :source 38 | 39 | def initialize(options = {}) 40 | options.each do |key, value| 41 | self.send("#{key}=", value) 42 | end 43 | 44 | @headers ||= {} 45 | @http_service ||= GData::HTTP::DefaultService 46 | @version ||= '2' 47 | @source ||= 'AnonymousApp' 48 | end 49 | 50 | # Sends an HTTP request with the given file as a stream 51 | def make_file_request(method, url, file_path, mime_type, entry = nil) 52 | if not File.readable?(file_path) 53 | raise ArgumentError, "File #{file_path} is not readable." 54 | end 55 | file = File.open(file_path, 'rb') 56 | @headers['Slug'] = File.basename(file_path) 57 | if entry 58 | @headers['MIME-Version'] = '1.0' 59 | body = GData::HTTP::MimeBody.new(entry, file, mime_type) 60 | @headers['Content-Type'] = body.content_type 61 | response = self.make_request(method, url, body) 62 | else 63 | @headers['Content-Type'] = mime_type 64 | response = self.make_request(method, url, file) 65 | end 66 | file.close 67 | return response 68 | end 69 | 70 | # Sends an HTTP request and return the response. 71 | def make_request(method, url, body = '') 72 | headers = self.prepare_headers 73 | request = GData::HTTP::Request.new(url, :headers => headers, 74 | :method => method, :body => body) 75 | 76 | if @auth_handler and @auth_handler.respond_to?(:sign_request!) 77 | @auth_handler.sign_request!(request) 78 | end 79 | 80 | service = http_service.new 81 | response = service.make_request(request) 82 | 83 | case response.status_code 84 | when 200, 201, 302 85 | #Do nothing, it's a success. 86 | when 401, 403 87 | raise AuthorizationError.new(response) 88 | when 400 89 | raise BadRequestError, response 90 | when 409 91 | raise VersionConflictError.new(response) 92 | when 500 93 | raise ServerError.new(response) 94 | else 95 | raise UnknownError.new(response) 96 | end 97 | 98 | return response 99 | end 100 | 101 | # Performs an HTTP GET against the API. 102 | def get(url) 103 | return self.make_request(:get, url) 104 | end 105 | 106 | # Performs an HTTP PUT against the API. 107 | def put(url, body) 108 | return self.make_request(:put, url, body) 109 | end 110 | 111 | # Performs an HTTP PUT with the given file 112 | def put_file(url, file_path, mime_type, entry = nil) 113 | return self.make_file_request(:put, url, file_path, mime_type, entry) 114 | end 115 | 116 | # Performs an HTTP POST against the API. 117 | def post(url, body) 118 | return self.make_request(:post, url, body) 119 | end 120 | 121 | # Performs an HTTP POST with the given file 122 | def post_file(url, file_path, mime_type, entry = nil) 123 | return self.make_file_request(:post, url, file_path, mime_type, entry) 124 | end 125 | 126 | # Performs an HTTP DELETE against the API. 127 | def delete(url) 128 | return self.make_request(:delete, url) 129 | end 130 | 131 | # Constructs some necessary headers for every request. 132 | def prepare_headers 133 | headers = @headers 134 | headers['GData-Version'] = @version 135 | headers['User-Agent'] = GData::Auth::SOURCE_LIB_STRING + @source 136 | # by default we assume we are sending Atom entries 137 | if not headers.has_key?('Content-Type') 138 | headers['Content-Type'] = 'application/atom+xml' 139 | end 140 | return headers 141 | end 142 | 143 | # Performs ClientLogin for the service. See GData::Auth::ClientLogin 144 | # for details. 145 | def clientlogin(username, password, captcha_token = nil, 146 | captcha_answer = nil, service = nil, account_type = nil) 147 | if service.nil? 148 | service = @clientlogin_service 149 | end 150 | options = { :account_type => account_type } 151 | self.auth_handler = GData::Auth::ClientLogin.new(service, options) 152 | if @clientlogin_url 153 | @auth_handler.auth_url = @clientlogin_url 154 | end 155 | source = GData::Auth::SOURCE_LIB_STRING + @source 156 | @auth_handler.get_token(username, password, source, captcha_token, captcha_answer) 157 | end 158 | 159 | def authsub_url(next_url, secure = false, session = true, domain = nil, 160 | scope = nil) 161 | if scope.nil? 162 | scope = @authsub_scope 163 | end 164 | GData::Auth::AuthSub.get_url(next_url, scope, secure, session, domain) 165 | end 166 | 167 | # Sets an AuthSub token for the service. 168 | def authsub_token=(token) 169 | self.auth_handler = GData::Auth::AuthSub.new(token) 170 | end 171 | 172 | # Sets a private key to use with AuthSub requests. 173 | def authsub_private_key=(key) 174 | if @auth_handler.class == GData::Auth::AuthSub 175 | @auth_handler.private_key = key 176 | else 177 | raise Error, "An AuthSub token must be set first." 178 | end 179 | end 180 | end 181 | end 182 | end 183 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. --------------------------------------------------------------------------------