picasa 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/README.md +25 -2
- data/extra/Thorfile +41 -0
- data/lib/picasa.rb +4 -0
- data/lib/picasa/api/album.rb +45 -14
- data/lib/picasa/api/base.rb +18 -0
- data/lib/picasa/api/photo.rb +30 -0
- data/lib/picasa/api/tag.rb +5 -16
- data/lib/picasa/client.rb +11 -0
- data/lib/picasa/connection.rb +34 -14
- data/lib/picasa/exceptions.rb +2 -0
- data/lib/picasa/file.rb +36 -0
- data/lib/picasa/presenter/album.rb +16 -1
- data/lib/picasa/presenter/album_list.rb +1 -1
- data/lib/picasa/presenter/photo.rb +5 -0
- data/lib/picasa/presenter/tag.rb +6 -1
- data/lib/picasa/presenter/tag_list.rb +1 -1
- data/lib/picasa/template.rb +25 -0
- data/lib/picasa/templates/new_album.xml.erb +19 -0
- data/lib/picasa/templates/new_photo.xml.erb +15 -0
- data/lib/picasa/utils.rb +1 -1
- data/lib/picasa/version.rb +1 -1
- data/test/api/album_test.rb +22 -0
- data/test/api/photo_test.rb +46 -0
- data/test/connection_test.rb +15 -11
- data/test/file_test.rb +29 -0
- data/test/fixtures/album/album-create.txt +21 -0
- data/test/fixtures/{auth/failure.txt → exceptions/forbidden.txt} +0 -0
- data/test/fixtures/{not_found.txt → exceptions/not_found.txt} +0 -0
- data/test/fixtures/exceptions/precondition_failed.txt +14 -0
- data/test/fixtures/lena.jpg +0 -0
- data/test/fixtures/photo/photo-created.txt +21 -0
- data/test/helper.rb +4 -0
- data/test/presenter/album_test.rb +16 -0
- data/test/presenter/photo_test.rb +4 -0
- data/test/presenter/tag_test.rb +4 -0
- data/test/template_test.rb +25 -0
- metadata +18 -4
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -19,17 +19,40 @@ client.album.list
|
|
19
19
|
|
20
20
|
client.album.show("album_id")
|
21
21
|
# => Picasa::Presenter::Album
|
22
|
+
|
23
|
+
client.photo.create("album_id", file_path: "path/to/my-photo.png")
|
24
|
+
# => Picasa::Presenter::Photo
|
22
25
|
```
|
23
26
|
|
24
27
|
If password is specified, all requests will be authenticated.
|
25
|
-
This affect results to contain private data.
|
28
|
+
This affect results to contain private data, however it can be controlled by `access` parameter.
|
29
|
+
|
30
|
+
## Caveats
|
31
|
+
|
32
|
+
Currently picasa wont work with `ox` xml parser.
|
33
|
+
Using `rexml` parser wont return `etag` attribute properly.
|
34
|
+
I recommend to use `libxml` or `nokogiri`.
|
35
|
+
|
36
|
+
## Extra
|
37
|
+
|
38
|
+
You can install thor script for uploading all photos from given directory:
|
39
|
+
|
40
|
+
```
|
41
|
+
thor install https://github.com/morgoth/picasa/raw/master/extra/Thorfile --as picasa_uploader --force
|
42
|
+
```
|
43
|
+
|
44
|
+
And then use it (it will create album taking title from folder name and upload all photos from that directory):
|
45
|
+
|
46
|
+
```
|
47
|
+
GOOGLE_USER_ID=your.email@gmail.com GOOGLE_PASSWORD=secret thor picasa_uploader:upload_all path-to-folder-with-photos
|
48
|
+
```
|
26
49
|
|
27
50
|
## Continuous Integration
|
28
51
|
[![Build Status](https://secure.travis-ci.org/morgoth/picasa.png)](http://travis-ci.org/morgoth/picasa)
|
29
52
|
|
30
53
|
## Contributors
|
31
54
|
|
32
|
-
* [Bram Wijnands](https://github.com/
|
55
|
+
* [Bram Wijnands](https://github.com/Bram--)
|
33
56
|
* [Rafael Souza](https://github.com/rafaels)
|
34
57
|
* [jsaak](https://github.com/jsaak)
|
35
58
|
* [Javier Guerra](https://github.com/javierg)
|
data/extra/Thorfile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "picasa"
|
2
|
+
|
3
|
+
# Temporary requirement
|
4
|
+
MultiXml.parser = :libxml
|
5
|
+
|
6
|
+
class PicasaUploader < Thor
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
desc "upload_all DIR", "Uploads all photos from given directory"
|
10
|
+
def upload_all(dir = File.basename(Dir.getwd))
|
11
|
+
require_credentials
|
12
|
+
album_presenter = create_album(File.basename(dir))
|
13
|
+
photos_number = 0
|
14
|
+
inside(dir, :verbose => true) do
|
15
|
+
Dir.entries(".").select { |e| e =~ /\.(jpg|jpeg|png|gif|bmp)$/i }.sort.each do |file|
|
16
|
+
create_photo(album_presenter, file)
|
17
|
+
photos_number += 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
say "Finished uploading #{photos_number} photos"
|
21
|
+
end
|
22
|
+
|
23
|
+
no_tasks do
|
24
|
+
def require_credentials
|
25
|
+
say "You must specify GOOGLE_USER_ID env variable" and exit unless ENV["GOOGLE_USER_ID"]
|
26
|
+
say "You must specify GOOGLE_PASSWORD env variable" and exit unless ENV["GOOGLE_PASSWORD"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_album(album)
|
30
|
+
say("Creating album: #{album}")
|
31
|
+
client = Picasa::Client.new(user_id: ENV["GOOGLE_USER_ID"], password: ENV["GOOGLE_PASSWORD"])
|
32
|
+
client.album.create(title: album)
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_photo(album, path)
|
36
|
+
say("Uploading photo #{path} to album #{album.title}")
|
37
|
+
client = Picasa::Client.new(user_id: ENV["GOOGLE_USER_ID"], password: ENV["GOOGLE_PASSWORD"])
|
38
|
+
client.photo.create(album.id, file_path: path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/picasa.rb
CHANGED
@@ -5,7 +5,11 @@ require "picasa/utils"
|
|
5
5
|
require "picasa/exceptions"
|
6
6
|
require "picasa/connection"
|
7
7
|
require "picasa/client"
|
8
|
+
require "picasa/file"
|
9
|
+
require "picasa/template"
|
10
|
+
|
8
11
|
require "picasa/api/album"
|
12
|
+
require "picasa/api/photo"
|
9
13
|
require "picasa/api/tag"
|
10
14
|
|
11
15
|
require "picasa/presenter/album"
|
data/lib/picasa/api/album.rb
CHANGED
@@ -1,22 +1,15 @@
|
|
1
|
+
require "picasa/api/base"
|
2
|
+
|
1
3
|
module Picasa
|
2
4
|
module API
|
3
|
-
class Album
|
4
|
-
attr_reader :user_id, :credentials
|
5
|
-
|
6
|
-
# @param [Hash] credentials
|
7
|
-
# @option credentials [String] :user_id google username/email
|
8
|
-
# @option credentials [String] :password password for given username/email
|
9
|
-
def initialize(credentials)
|
10
|
-
if MultiXml.parser.to_s == "MultiXml::Parsers::Ox"
|
11
|
-
raise StandardError, "MultiXml parser is set to :ox - picasa gem will not work with it currently, use one of: :libxml, :nokogiri, :rexml"
|
12
|
-
end
|
13
|
-
@user_id = credentials.fetch(:user_id)
|
14
|
-
@credentials = credentials
|
15
|
-
end
|
16
|
-
|
5
|
+
class Album < Base
|
17
6
|
# Returns album list
|
18
7
|
#
|
19
8
|
# @param [Hash] options additional options included in request
|
9
|
+
# @option options [all, private, public, visible] :access which data should be retrieved when authenticated
|
10
|
+
# @option options [String] :fields which fields should be retrieved https://developers.google.com/gdata/docs/2.0/reference#PartialResponseRequest
|
11
|
+
# @option options [String, Integer] :max_results how many albums response should include
|
12
|
+
# @option options [String, Integer] :start_index 1-based index of the first result to be retrieved
|
20
13
|
#
|
21
14
|
# @return [Presenter::AlbumList]
|
22
15
|
def list(options = {})
|
@@ -41,6 +34,44 @@ module Picasa
|
|
41
34
|
|
42
35
|
Presenter::Album.new(parsed_body["feed"])
|
43
36
|
end
|
37
|
+
|
38
|
+
# Creates album
|
39
|
+
#
|
40
|
+
# @param [Hash] params album parameters
|
41
|
+
# @option options [String] :title title of album (required)
|
42
|
+
# @option options [String] :summary summary of album
|
43
|
+
# @option options [String] :location location of album photos (i.e. Poland)
|
44
|
+
# @option options [String] :access [public, private, protected]
|
45
|
+
# @option options [String] :timestamp timestamp of album (default to now)
|
46
|
+
# @option options [String] :keywords keywords (i.e. "vacation, poland")
|
47
|
+
#
|
48
|
+
# @return [Presenter::Album]
|
49
|
+
def create(params = {})
|
50
|
+
params[:title] || raise(ArgumentError, "You must specify title")
|
51
|
+
params[:timestamp] ||= Time.now.to_i
|
52
|
+
|
53
|
+
template = Template.new(:new_album, params)
|
54
|
+
uri = URI.parse("/data/feed/api/user/#{user_id}")
|
55
|
+
parsed_body = Connection.new(credentials).post(uri.path, template.render)
|
56
|
+
Presenter::Album.new(parsed_body["entry"])
|
57
|
+
end
|
58
|
+
|
59
|
+
# Destroys given album
|
60
|
+
#
|
61
|
+
# @param [String] album_id album id
|
62
|
+
# @param [Hash] options request parameters
|
63
|
+
# @option options [String] :etag destroys only when ETag matches - protects before destroying other client changes
|
64
|
+
#
|
65
|
+
# @return [true]
|
66
|
+
# @raise [NotFoundError] raised when album cannot be found
|
67
|
+
# @raise [PreconditionFailedError] raised when ETag does not match
|
68
|
+
def destroy(album_id, options = {})
|
69
|
+
headers = {"If-Match" => options.fetch(:etag, "*")}
|
70
|
+
uri = URI.parse("/data/entry/api/user/#{user_id}/albumid/#{album_id}")
|
71
|
+
Connection.new(credentials).delete(uri.path, headers)
|
72
|
+
true
|
73
|
+
end
|
74
|
+
alias :delete :destroy
|
44
75
|
end
|
45
76
|
end
|
46
77
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Picasa
|
2
|
+
module API
|
3
|
+
class Base
|
4
|
+
attr_reader :user_id, :credentials
|
5
|
+
|
6
|
+
# @param [Hash] credentials
|
7
|
+
# @option credentials [String] :user_id google username/email
|
8
|
+
# @option credentials [String] :password password for given username/email
|
9
|
+
def initialize(credentials)
|
10
|
+
if MultiXml.parser.to_s == "MultiXml::Parsers::Ox"
|
11
|
+
raise StandardError, "MultiXml parser is set to :ox - picasa gem will not work with it currently, use one of: :libxml, :nokogiri, :rexml"
|
12
|
+
end
|
13
|
+
@user_id = credentials.fetch(:user_id)
|
14
|
+
@credentials = credentials
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "picasa/api/base"
|
2
|
+
|
3
|
+
module Picasa
|
4
|
+
module API
|
5
|
+
class Photo < Base
|
6
|
+
# Creates photo for given album
|
7
|
+
#
|
8
|
+
# @param [String] album_id album id
|
9
|
+
# @param [Hash] options request parameters
|
10
|
+
# @option options [String] :file_path path to photo file, rest of required attributes might be guessed based on file (i.e. "/home/john/Images/me.png")
|
11
|
+
# @option options [String] :title title of photo
|
12
|
+
# @option options [String] :summary summary of photo
|
13
|
+
# @option options [String] :binary binary data (i.e. File.open("my-photo.png", "rb").read)
|
14
|
+
# @option options [String] :content_type ["image/jpeg", "image/png", "image/bmp", "image/gif"] content type of given image
|
15
|
+
def create(album_id, params = {})
|
16
|
+
file = params[:file_path] ? File.new(params.delete(:file_path)) : nil
|
17
|
+
params[:boundary] ||= "===============PicasaRubyGem=="
|
18
|
+
params[:title] ||= (file && file.name) || raise(ArgumentError.new("title must be specified"))
|
19
|
+
params[:binary] ||= (file && file.binary) || raise(ArgumentError.new("binary must be specified"))
|
20
|
+
params[:content_type] ||= (file && file.content_type) || raise(ArgumentError.new("content_type must be specified"))
|
21
|
+
template = Template.new(:new_photo, params)
|
22
|
+
headers = {"Content-Type" => "multipart/related; boundary=\"#{params[:boundary]}\""}
|
23
|
+
|
24
|
+
uri = URI.parse("/data/feed/api/user/#{user_id}/albumid/#{album_id}")
|
25
|
+
parsed_body = Connection.new(credentials).post(uri.path, template.render, headers)
|
26
|
+
Presenter::Photo.new(parsed_body["entry"])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/picasa/api/tag.rb
CHANGED
@@ -1,24 +1,13 @@
|
|
1
|
+
require "picasa/api/base"
|
2
|
+
|
1
3
|
module Picasa
|
2
4
|
module API
|
3
|
-
class Tag
|
4
|
-
attr_reader :user_id, :credentials
|
5
|
-
|
6
|
-
# @param [Hash] credentials
|
7
|
-
# @option credentials [String] :user_id google username/email
|
8
|
-
# @option credentials [String] :password password for given username/email
|
9
|
-
def initialize(credentials)
|
10
|
-
if MultiXml.parser.to_s == "MultiXml::Parsers::Ox"
|
11
|
-
raise StandardError, "MultiXml parser is set to :ox - picasa gem will not work with it currently, use one of: :libxml, :nokogiri, :rexml"
|
12
|
-
end
|
13
|
-
@user_id = credentials.fetch(:user_id)
|
14
|
-
@credentials = credentials
|
15
|
-
end
|
16
|
-
|
5
|
+
class Tag < Base
|
17
6
|
# Returns tag list - when album_id is not specified, list of user tags will be returned
|
18
7
|
#
|
19
8
|
# @param [Hash] options additional options included in request
|
20
|
-
# @option
|
21
|
-
# @option
|
9
|
+
# @option options [String] :album_id retrieve tags for given album
|
10
|
+
# @option options [String] :photo_id retrieve tags for given photo (album_id must be provided)
|
22
11
|
#
|
23
12
|
# @return [Presenter::TagList]
|
24
13
|
def list(options = {})
|
data/lib/picasa/client.rb
CHANGED
@@ -21,6 +21,17 @@ module Picasa
|
|
21
21
|
API::Album.new(credentials)
|
22
22
|
end
|
23
23
|
|
24
|
+
# @return [API::Photo]
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# client = Picasa::Client.new(user_id: "my.email@google.com", password: "secret")
|
28
|
+
# photo = client.photo.create("album-id", title: "My picture", binary: "image-binary-data", content_type: "image/jpeg")
|
29
|
+
# photo.id
|
30
|
+
# # => "4322232322421"
|
31
|
+
def photo
|
32
|
+
API::Photo.new(credentials)
|
33
|
+
end
|
34
|
+
|
24
35
|
# @return [API::Tag]
|
25
36
|
#
|
26
37
|
# @example
|
data/lib/picasa/connection.rb
CHANGED
@@ -23,6 +23,23 @@ module Picasa
|
|
23
23
|
|
24
24
|
path = path_with_params(path, params)
|
25
25
|
request = Net::HTTP::Get.new(path, headers)
|
26
|
+
response = handle_response(http.request(request))
|
27
|
+
MultiXml.parse(response.body)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(path, body, custom_headers = {})
|
31
|
+
authenticate if auth?
|
32
|
+
|
33
|
+
request = Net::HTTP::Post.new(path, headers.merge(custom_headers))
|
34
|
+
request.body = body
|
35
|
+
response = handle_response(http.request(request))
|
36
|
+
MultiXml.parse(response.body)
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete(path, custom_headers = {})
|
40
|
+
authenticate if auth?
|
41
|
+
|
42
|
+
request = Net::HTTP::Delete.new(path, headers.merge(custom_headers))
|
26
43
|
handle_response(http.request(request))
|
27
44
|
end
|
28
45
|
|
@@ -43,16 +60,24 @@ module Picasa
|
|
43
60
|
def handle_response(response)
|
44
61
|
case response.code.to_i
|
45
62
|
when 200...300
|
46
|
-
|
63
|
+
response
|
64
|
+
when 403
|
65
|
+
raise ForbiddenError.new(response.body, response)
|
47
66
|
when 404
|
48
67
|
raise NotFoundError.new(response.body, response)
|
68
|
+
when 412
|
69
|
+
raise PreconditionFailedError.new(response.body, response)
|
49
70
|
else
|
50
|
-
raise ResponseError.new(
|
71
|
+
raise ResponseError.new(response.body, response)
|
51
72
|
end
|
52
73
|
end
|
53
74
|
|
54
75
|
def headers
|
55
|
-
{
|
76
|
+
{
|
77
|
+
"User-Agent" => client_name,
|
78
|
+
"GData-Version" => API_VERSION,
|
79
|
+
"Content-Type" => "application/atom+xml"
|
80
|
+
}.tap do |headers|
|
56
81
|
headers["Authorization"] = "GoogleLogin auth=#{@auth_key}" if @auth_key
|
57
82
|
end
|
58
83
|
end
|
@@ -61,23 +86,14 @@ module Picasa
|
|
61
86
|
!password.nil?
|
62
87
|
end
|
63
88
|
|
64
|
-
def validate_email!
|
65
|
-
unless user_id =~ /[a-z0-9][a-z0-9._%+-]+[a-z0-9]@[a-z0-9][a-z0-9.-][a-z0-9]+\.[a-z]{2,6}/i
|
66
|
-
raise ArgumentError.new("user_id must be a valid E-mail address when authentication is used.")
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
89
|
def authenticate
|
71
|
-
validate_email!
|
72
|
-
|
73
90
|
data = inline_params({"accountType" => "HOSTED_OR_GOOGLE",
|
74
91
|
"Email" => user_id,
|
75
92
|
"Passwd" => password,
|
76
93
|
"service" => "lh2",
|
77
|
-
"source" =>
|
94
|
+
"source" => client_name})
|
78
95
|
|
79
|
-
response = http(API_AUTH_URL).post("/accounts/ClientLogin", data)
|
80
|
-
raise ResponseError.new(response.body, response) unless response.is_a? Net::HTTPSuccess
|
96
|
+
response = handle_response(http(API_AUTH_URL).post("/accounts/ClientLogin", data))
|
81
97
|
|
82
98
|
@auth_key = extract_auth_key(response.body)
|
83
99
|
end
|
@@ -87,5 +103,9 @@ module Picasa
|
|
87
103
|
params = Hash[response]
|
88
104
|
params["Auth"]
|
89
105
|
end
|
106
|
+
|
107
|
+
def client_name
|
108
|
+
"ruby-gem-v#{Picasa::VERSION}"
|
109
|
+
end
|
90
110
|
end
|
91
111
|
end
|
data/lib/picasa/exceptions.rb
CHANGED
data/lib/picasa/file.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Picasa
|
2
|
+
class File
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
@path = path || raise(ArgumentError.new("path not specified"))
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
@name ||= ::File.basename(path, ".*")
|
11
|
+
end
|
12
|
+
|
13
|
+
def extension
|
14
|
+
@extension ||= ::File.extname(path)[1..-1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def binary
|
18
|
+
@binary ||= ::File.open(path, "rb").read
|
19
|
+
end
|
20
|
+
|
21
|
+
def content_type
|
22
|
+
@content_type ||= case extension
|
23
|
+
when /^jpe?g$/i
|
24
|
+
"image/jpeg"
|
25
|
+
when /^gif$/i
|
26
|
+
"image/gif"
|
27
|
+
when /^png$/i
|
28
|
+
"image/png"
|
29
|
+
when /^bmp$/i
|
30
|
+
"image/bmp"
|
31
|
+
else
|
32
|
+
raise StandarError.new("Content type cannot be guessed from file extension: #{extension}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -16,7 +16,7 @@ module Picasa
|
|
16
16
|
|
17
17
|
# @return [Array<Presenter::Link>]
|
18
18
|
def links
|
19
|
-
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
19
|
+
@links ||= array_wrap(safe_retrieve(parsed_body, "link")).map { |link| Link.new(link) }
|
20
20
|
end
|
21
21
|
|
22
22
|
# @return [Presenter::Media]
|
@@ -34,6 +34,11 @@ module Picasa
|
|
34
34
|
@updated ||= map_to_date(safe_retrieve(parsed_body, "updated"))
|
35
35
|
end
|
36
36
|
|
37
|
+
# @return [String]
|
38
|
+
def etag
|
39
|
+
@etag ||= safe_retrieve(parsed_body, "etag")
|
40
|
+
end
|
41
|
+
|
37
42
|
# @return [String]
|
38
43
|
def title
|
39
44
|
@title ||= safe_retrieve(parsed_body, "title")
|
@@ -88,6 +93,16 @@ module Picasa
|
|
88
93
|
def nickname
|
89
94
|
@nickname ||= safe_retrieve(parsed_body, "nickname")
|
90
95
|
end
|
96
|
+
|
97
|
+
# @return [true, false, nil]
|
98
|
+
def allow_prints
|
99
|
+
@allow_prints ||= map_to_boolean(safe_retrieve(parsed_body, "allowPrints"))
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [true, false, nil]
|
103
|
+
def allow_downloads
|
104
|
+
@allow_downloads ||= map_to_boolean(safe_retrieve(parsed_body, "allowDownloads"))
|
105
|
+
end
|
91
106
|
end
|
92
107
|
end
|
93
108
|
end
|
@@ -16,7 +16,7 @@ module Picasa
|
|
16
16
|
|
17
17
|
# @return [Array<Presenter::Link>]
|
18
18
|
def links
|
19
|
-
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
19
|
+
@links ||= array_wrap(safe_retrieve(parsed_body, "link")).map { |link| Link.new(link) }
|
20
20
|
end
|
21
21
|
|
22
22
|
# @return [String]
|
@@ -23,6 +23,11 @@ module Picasa
|
|
23
23
|
@id ||= array_wrap(safe_retrieve(parsed_body, "id"))[1]
|
24
24
|
end
|
25
25
|
|
26
|
+
# @return [String]
|
27
|
+
def etag
|
28
|
+
@etag ||= safe_retrieve(parsed_body, "etag")
|
29
|
+
end
|
30
|
+
|
26
31
|
# @return [DateTime]
|
27
32
|
def published
|
28
33
|
@published ||= map_to_date(safe_retrieve(parsed_body, "published"))
|
data/lib/picasa/presenter/tag.rb
CHANGED
@@ -10,7 +10,7 @@ module Picasa
|
|
10
10
|
|
11
11
|
# @return [Array<Presenter::Link>]
|
12
12
|
def links
|
13
|
-
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
13
|
+
@links ||= array_wrap(safe_retrieve(parsed_body, "link")).map { |link| Link.new(link) }
|
14
14
|
end
|
15
15
|
|
16
16
|
# @return [DateTime]
|
@@ -23,6 +23,11 @@ module Picasa
|
|
23
23
|
@title ||= safe_retrieve(parsed_body, "title")
|
24
24
|
end
|
25
25
|
|
26
|
+
# @return [String]
|
27
|
+
def etag
|
28
|
+
@etag ||= safe_retrieve(parsed_body, "etag")
|
29
|
+
end
|
30
|
+
|
26
31
|
# @return [String]
|
27
32
|
def summary
|
28
33
|
@summary ||= safe_retrieve(parsed_body, "summary")
|
@@ -16,7 +16,7 @@ module Picasa
|
|
16
16
|
|
17
17
|
# @return [Array<Presenter::Link>]
|
18
18
|
def links
|
19
|
-
@links ||= safe_retrieve(parsed_body, "link").map { |link| Link.new(link) }
|
19
|
+
@links ||= array_wrap(safe_retrieve(parsed_body, "link")).map { |link| Link.new(link) }
|
20
20
|
end
|
21
21
|
|
22
22
|
# @return [String]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "erb"
|
3
|
+
|
4
|
+
module Picasa
|
5
|
+
class Template
|
6
|
+
attr_reader :name, :params
|
7
|
+
|
8
|
+
def initialize(name, params)
|
9
|
+
@name = name
|
10
|
+
@params = params
|
11
|
+
end
|
12
|
+
|
13
|
+
def file
|
14
|
+
@file ||= IO.read(::File.expand_path("../templates/#{name}.xml.erb", __FILE__))
|
15
|
+
end
|
16
|
+
|
17
|
+
def struct
|
18
|
+
@struct ||= OpenStruct.new(params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def render
|
22
|
+
ERB.new(file).result(struct.instance_eval { binding })
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gphoto="http://schemas.google.com/photos/2007">
|
2
|
+
<title type="text"><%= title %></title>
|
3
|
+
<% if summary %>
|
4
|
+
<summary type="text"><%= summary %></summary>
|
5
|
+
<% end %>
|
6
|
+
<% if location %>
|
7
|
+
<gphoto:location><%= location %></gphoto:location>
|
8
|
+
<% end %>
|
9
|
+
<% if access %>
|
10
|
+
<gphoto:access><%= access %></gphoto:access>
|
11
|
+
<% end %>
|
12
|
+
<gphoto:timestamp><%= timestamp %></gphoto:timestamp>
|
13
|
+
<% if keywords %>
|
14
|
+
<media:group>
|
15
|
+
<media:keywords><%= keywords %></media:keywords>
|
16
|
+
</media:group>
|
17
|
+
<% end %>
|
18
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#album"></category>
|
19
|
+
</entry>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
--<%= boundary %>
|
2
|
+
Content-type: application/atom+xml
|
3
|
+
|
4
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
5
|
+
<title><%= title %></title>
|
6
|
+
<% if summary %>
|
7
|
+
<summary><%= summary %></summary>
|
8
|
+
<% end %>
|
9
|
+
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo"/>
|
10
|
+
</entry>
|
11
|
+
--<%= boundary %>
|
12
|
+
Content-type: <%= content_type %>
|
13
|
+
|
14
|
+
<%= binary %>
|
15
|
+
--<%= boundary %>
|
data/lib/picasa/utils.rb
CHANGED
data/lib/picasa/version.rb
CHANGED
data/test/api/album_test.rb
CHANGED
@@ -21,4 +21,26 @@ describe Picasa::API::Album do
|
|
21
21
|
assert_equal "Wojciech Wnętrzak", album_show.author.name
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
describe "#create" do
|
26
|
+
it "gives correct parsed body fragment" do
|
27
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("auth/success.txt"))
|
28
|
+
stub_request(:post, "https://picasaweb.google.com/data/feed/api/user/w.wnetrzak@gmail.com").to_return(fixture("album/album-create.txt"))
|
29
|
+
|
30
|
+
album_show = Picasa::API::Album.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret").create(:title => "album")
|
31
|
+
|
32
|
+
assert_equal "Wojciech Wnętrzak", album_show.author.name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#destroy" do
|
37
|
+
it "gives true when success" do
|
38
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("auth/success.txt"))
|
39
|
+
stub_request(:delete, "https://picasaweb.google.com/data/entry/api/user/w.wnetrzak@gmail.com/albumid/123").to_return(:status => 200, :body => "")
|
40
|
+
|
41
|
+
result = Picasa::API::Album.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret").destroy("123")
|
42
|
+
|
43
|
+
assert_equal true, result
|
44
|
+
end
|
45
|
+
end
|
24
46
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require "helper"
|
3
|
+
|
4
|
+
describe Picasa::API::Photo do
|
5
|
+
describe "#create" do
|
6
|
+
it "gives correct parsed body fragment" do
|
7
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("auth/success.txt"))
|
8
|
+
stub_request(:post, "https://picasaweb.google.com/data/feed/api/user/w.wnetrzak@gmail.com/albumid/123").to_return(fixture("photo/photo-created.txt"))
|
9
|
+
|
10
|
+
photo = Picasa::API::Photo.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret")
|
11
|
+
photo_create = photo.create("123", :title => "test", :binary => "binary", :content_type => "image/png")
|
12
|
+
|
13
|
+
assert_equal 27040, photo_create.size
|
14
|
+
end
|
15
|
+
|
16
|
+
it "raises ArgumentError when no title" do
|
17
|
+
photo = Picasa::API::Photo.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret")
|
18
|
+
assert_raises Picasa::ArgumentError, /title/ do
|
19
|
+
photo.create("123", :binary => "binary", :content_type => "image/png")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises ArgumentError when no binary" do
|
24
|
+
photo = Picasa::API::Photo.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret")
|
25
|
+
assert_raises Picasa::ArgumentError, /binary/ do
|
26
|
+
photo.create("123", :title => "test", :content_type => "image/png")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises ArgumentError when no content type" do
|
31
|
+
photo = Picasa::API::Photo.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret")
|
32
|
+
assert_raises Picasa::ArgumentError, /content_type/ do
|
33
|
+
photo.create("123", :title => "test", :binary => "binary")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "guesses required attributes from file path" do
|
38
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("auth/success.txt"))
|
39
|
+
stub_request(:post, "https://picasaweb.google.com/data/feed/api/user/w.wnetrzak@gmail.com/albumid/123").to_return(fixture("photo/photo-created.txt"))
|
40
|
+
|
41
|
+
photo = Picasa::API::Photo.new(:user_id => "w.wnetrzak@gmail.com", :password => "secret")
|
42
|
+
|
43
|
+
assert photo.create("123", :file_path => image_path("lena.jpg"))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/test/connection_test.rb
CHANGED
@@ -41,13 +41,25 @@ describe Picasa::Connection do
|
|
41
41
|
connection = Picasa::Connection.new(:user_id => "john.doe@domain.com")
|
42
42
|
uri = URI.parse("/data/feed/api/user/#{connection.user_id}/albumid/non-existing")
|
43
43
|
|
44
|
-
stub_request(:get, "https://picasaweb.google.com" + uri.path).to_return(fixture("not_found.txt"))
|
44
|
+
stub_request(:get, "https://picasaweb.google.com" + uri.path).to_return(fixture("exceptions/not_found.txt"))
|
45
45
|
|
46
46
|
assert_raises Picasa::NotFoundError, "Invalid entity id: non-existing" do
|
47
47
|
connection.get(uri.path)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
it "raises PreconditionFailed exception when 412 returned" do
|
52
|
+
connection = Picasa::Connection.new(:user_id => "john.doe@domain.com", :password => "secret")
|
53
|
+
uri = URI.parse("/data/feed/api/user/#{connection.user_id}/albumid/123")
|
54
|
+
|
55
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("auth/success.txt"))
|
56
|
+
stub_request(:delete, "https://picasaweb.google.com" + uri.path).to_return(fixture("exceptions/precondition_failed.txt"))
|
57
|
+
|
58
|
+
assert_raises Picasa::PreconditionFailedError, "Mismatch: etags = [oldetag], version = [7]" do
|
59
|
+
connection.delete(uri.path, {"If-Match" => "oldetag"})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
51
63
|
describe "authentication" do
|
52
64
|
it "successfully authenticates" do
|
53
65
|
connection = Picasa::Connection.new(:user_id => "john.doe@domain.com", :password => "secret")
|
@@ -60,21 +72,13 @@ describe Picasa::Connection do
|
|
60
72
|
refute_nil connection.get(uri.path)
|
61
73
|
end
|
62
74
|
|
63
|
-
it "raises ArgumentError when invalid email given" do
|
64
|
-
connection = Picasa::Connection.new(:user_id => "john.doe", :password => "secret")
|
65
|
-
|
66
|
-
assert_raises(Picasa::ArgumentError) do
|
67
|
-
connection.get("/")
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
75
|
it "raises an ResponseError when authentication failed" do
|
72
76
|
connection = Picasa::Connection.new(:user_id => "john.doe@domain.com", :password => "secret")
|
73
77
|
uri = URI.parse("/data/feed/api/user/#{connection.user_id}")
|
74
78
|
|
75
|
-
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("
|
79
|
+
stub_request(:post, "https://www.google.com/accounts/ClientLogin").to_return(fixture("exceptions/forbidden.txt"))
|
76
80
|
|
77
|
-
assert_raises(Picasa::
|
81
|
+
assert_raises(Picasa::ForbiddenError) do
|
78
82
|
connection.get(uri.path)
|
79
83
|
end
|
80
84
|
end
|
data/test/file_test.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe Picasa::File do
|
4
|
+
it "raises argument error when nil path given" do
|
5
|
+
assert_raises Picasa::ArgumentError do
|
6
|
+
Picasa::File.new(nil)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "it returns file name" do
|
11
|
+
file = Picasa::File.new(image_path("lena.jpg"))
|
12
|
+
assert_equal "lena", file.name
|
13
|
+
end
|
14
|
+
|
15
|
+
it "it returns file extension" do
|
16
|
+
file = Picasa::File.new(image_path("lena.jpg"))
|
17
|
+
assert_equal "jpg", file.extension
|
18
|
+
end
|
19
|
+
|
20
|
+
it "it guesses content type" do
|
21
|
+
file = Picasa::File.new(image_path("lena.jpg"))
|
22
|
+
assert_equal "image/jpeg", file.content_type
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns binary read file" do
|
26
|
+
file = Picasa::File.new(image_path("lena.jpg"))
|
27
|
+
assert_equal String, file.binary.class
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
HTTP/1.1 201 Created
|
2
|
+
Gdata-version: 2.0
|
3
|
+
Content-length: 2988
|
4
|
+
Via: HTTP/1.1 GWA
|
5
|
+
Content-location: https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5783214424453412737
|
6
|
+
X-content-type-options: nosniff
|
7
|
+
Etag: "YD0qeyI."
|
8
|
+
Set-cookie: _rtok=v2BIV10GEHe2; Path=/; Secure; HttpOnly, S=photos_html=TyVjxRd5Em09qzhPl6Kjsw; Domain=.google.com; Path=/; Secure; HttpOnly
|
9
|
+
Expires: Sat, 01 Sep 2012 14:25:36 GMT
|
10
|
+
Vary: Accept, X-GData-Authorization, GData-Version
|
11
|
+
X-google-cache-control: remote-fetch
|
12
|
+
Server: GSE
|
13
|
+
X-xss-protection: 1; mode=block
|
14
|
+
Location: https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5783214424453412737
|
15
|
+
Cache-control: private, max-age=0, must-revalidate, no-transform
|
16
|
+
Date: Sat, 01 Sep 2012 14:25:36 GMT
|
17
|
+
X-frame-options: SAMEORIGIN
|
18
|
+
Content-type: application/atom+xml; charset=UTF-8; type=entry
|
19
|
+
-content-encoding: gzip
|
20
|
+
|
21
|
+
<?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:app='http://www.w3.org/2007/app' xmlns:gphoto='http://schemas.google.com/photos/2007' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:gml='http://www.opengis.net/gml' xmlns:georss='http://www.georss.org/georss' gd:etag='"YD0qeyI."'><id>https://picasaweb.google.com/data/entry/user/106136347770555028022/albumid/5783214424453412737</id><published>1970-01-16T14:01:49.000Z</published><updated>2012-09-01T14:25:36.447Z</updated><app:edited>2012-09-01T14:25:36.447Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#album'/><title>Trip To Poland</title><summary>This was the recent trip I took to Poland.</summary><rights>protected</rights><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://picasaweb.google.com/data/feed/api/user/106136347770555028022/albumid/5783214424453412737'/><link rel='alternate' type='text/html' href='https://picasaweb.google.com/106136347770555028022/TripToPoland'/><link rel='self' type='application/atom+xml' href='https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5783214424453412737'/><link rel='edit' type='application/atom+xml' href='https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5783214424453412737'/><link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5783214424453412737/acl'/><author><name>Wojciech Wnętrzak</name><uri>https://picasaweb.google.com/106136347770555028022</uri></author><gphoto:id>5783214424453412737</gphoto:id><gphoto:name>TripToPoland</gphoto:name><gphoto:location>Poland</gphoto:location><gphoto:access>protected</gphoto:access><gphoto:timestamp>1346509000</gphoto:timestamp><gphoto:numphotos>0</gphoto:numphotos><gphoto:numphotosremaining>1000</gphoto:numphotosremaining><gphoto:bytesUsed>0</gphoto:bytesUsed><gphoto:user>106136347770555028022</gphoto:user><gphoto:nickname>Wojciech Wnętrzak</gphoto:nickname><media:group><media:content url='https://lh3.googleusercontent.com/-8od2ksbQgT0/UEIa4NV194E/AAAAAAAAAqI/XIYGNrflH9A/TripToPoland.jpg' type='image/jpeg' medium='image'/><media:credit>Wojciech Wnętrzak</media:credit><media:description type='plain'>This was the recent trip I took to Poland.</media:description><media:keywords/><media:thumbnail url='https://lh3.googleusercontent.com/-8od2ksbQgT0/UEIa4NV194E/AAAAAAAAAqI/XIYGNrflH9A/s160-c/TripToPoland.jpg' height='160' width='160'/><media:title type='plain'>Trip To Poland</media:title></media:group><georss:where><gml:Envelope><gml:lowerCorner>49.0025444 14.1336215</gml:lowerCorner><gml:upperCorner>54.8363315 24.1566505</gml:upperCorner></gml:Envelope><gml:Point><gml:pos>51.919438 19.145136</gml:pos></gml:Point></georss:where></entry>
|
File without changes
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
HTTP/1.1 412 Precondition Failed
|
2
|
+
Expires: Sat, 01 Sep 2012 17:21:46 GMT
|
3
|
+
Date: Sat, 01 Sep 2012 17:21:46 GMT
|
4
|
+
Cache-Control: private, max-age=0, must-revalidate
|
5
|
+
Set-Cookie: _rtok=3ODY353H4sXQ; Path=/; Secure; HttpOnly
|
6
|
+
Set-Cookie: S=photos_html=kOBZzBdZTgXA12OVzxVTbg; Domain=.google.com; Path=/; Secure; HttpOnly
|
7
|
+
Content-Type: text/html; charset=UTF-8
|
8
|
+
X-Content-Type-Options: nosniff
|
9
|
+
X-Frame-Options: SAMEORIGIN
|
10
|
+
X-XSS-Protection: 1; mode=block
|
11
|
+
Server: GSE
|
12
|
+
Transfer-Encoding: chunked
|
13
|
+
|
14
|
+
Mismatch: etags = [oldetag], version = [7]
|
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
HTTP/1.1 201 Created
|
2
|
+
Gdata-version: 2.0
|
3
|
+
Content-length: 3698
|
4
|
+
Via: HTTP/1.1 GWA
|
5
|
+
Content-location: https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834
|
6
|
+
X-content-type-options: nosniff
|
7
|
+
Etag: "YD0qeyI."
|
8
|
+
Set-cookie: _rtok=RJK5U_sWX0B8; Path=/; Secure; HttpOnly, S=photos_html=1MH7BnwEbzDbPVcrJGKtlw; Domain=.google.com; Path=/; Secure; HttpOnly
|
9
|
+
Expires: Fri, 31 Aug 2012 19:19:21 GMT
|
10
|
+
Vary: Accept, X-GData-Authorization, GData-Version
|
11
|
+
X-google-cache-control: remote-fetch
|
12
|
+
Server: GSE
|
13
|
+
X-xss-protection: 1; mode=block
|
14
|
+
Location: https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834
|
15
|
+
Cache-control: private, max-age=0, must-revalidate, no-transform
|
16
|
+
Date: Fri, 31 Aug 2012 19:19:21 GMT
|
17
|
+
X-frame-options: SAMEORIGIN
|
18
|
+
Content-type: application/atom+xml; charset=UTF-8; type=entry
|
19
|
+
-content-encoding: gzip
|
20
|
+
|
21
|
+
<?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:exif='http://schemas.google.com/photos/exif/2007' xmlns:app='http://www.w3.org/2007/app' xmlns:gphoto='http://schemas.google.com/photos/2007' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='"YD0qeyI."'><id>https://picasaweb.google.com/data/entry/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834</id><published>2012-08-31T19:19:20.000Z</published><updated>2012-08-31T19:19:20.882Z</updated><app:edited>2012-08-31T19:19:20.882Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#photo'/><title>ancient-test.jpg</title><summary>sent from playground</summary><content type='image/jpeg' src='https://lh5.googleusercontent.com/-HawhXkeW2Y4/UEEOOB0TuUI/AAAAAAAAAos/V1lCZ7oNAEg/ancient-test.jpg'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://picasaweb.google.com/data/feed/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834'/><link rel='alternate' type='text/html' href='https://picasaweb.google.com/106136347770555028022/PrivateTesting#5782919030689216834'/><link rel='http://schemas.google.com/photos/2007#canonical' type='text/html' href='https://picasaweb.google.com/lh/photo/HerZrwYwEPv8XgInPPde-NMTjNZETYmyPJy0liipFm0'/><link rel='self' type='application/atom+xml' href='https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834'/><link rel='edit' type='application/atom+xml' href='https://picasaweb.google.com/data/entry/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834'/><link rel='edit-media' type='image/jpeg' href='https://picasaweb.google.com/data/media/api/user/106136347770555028022/albumid/5782912491601845665/photoid/5782919030689216834'/><link rel='http://schemas.google.com/photos/2007#report' type='text/html' href='https://picasaweb.google.com/lh/reportAbuse?uname=106136347770555028022&aid=5782912491601845665&iid=5782919030689216834'/><gphoto:id>5782919030689216834</gphoto:id><gphoto:albumid>5782912491601845665</gphoto:albumid><gphoto:access>only_you</gphoto:access><gphoto:width>473</gphoto:width><gphoto:height>506</gphoto:height><gphoto:size>27040</gphoto:size><gphoto:checksum/><gphoto:timestamp>1346440760000</gphoto:timestamp><gphoto:imageVersion>651</gphoto:imageVersion><gphoto:commentingEnabled>true</gphoto:commentingEnabled><gphoto:commentCount>0</gphoto:commentCount><gphoto:license id='0' name='Wszelkie prawa zastrzeżone' url=''>ALL_RIGHTS_RESERVED</gphoto:license><exif:tags><exif:imageUniqueID>6b5722298561a74e1476868e2ae28b7d</exif:imageUniqueID></exif:tags><media:group><media:content url='https://lh5.googleusercontent.com/-HawhXkeW2Y4/UEEOOB0TuUI/AAAAAAAAAos/V1lCZ7oNAEg/ancient-test.jpg' height='506' width='473' type='image/jpeg' medium='image'/><media:credit>Wojciech Wnętrzak</media:credit><media:description type='plain'>sent from playground</media:description><media:keywords/><media:thumbnail url='https://lh5.googleusercontent.com/-HawhXkeW2Y4/UEEOOB0TuUI/AAAAAAAAAos/V1lCZ7oNAEg/s72/ancient-test.jpg' height='72' width='68'/><media:thumbnail url='https://lh5.googleusercontent.com/-HawhXkeW2Y4/UEEOOB0TuUI/AAAAAAAAAos/V1lCZ7oNAEg/s144/ancient-test.jpg' height='144' width='135'/><media:thumbnail url='https://lh5.googleusercontent.com/-HawhXkeW2Y4/UEEOOB0TuUI/AAAAAAAAAos/V1lCZ7oNAEg/s288/ancient-test.jpg' height='288' width='270'/><media:title type='plain'>ancient-test.jpg</media:title></media:group></entry>
|
data/test/helper.rb
CHANGED
@@ -14,6 +14,10 @@ class MiniTest::Unit::TestCase
|
|
14
14
|
WebMock.disable_net_connect!
|
15
15
|
end
|
16
16
|
|
17
|
+
def image_path(filename)
|
18
|
+
::File.join("test", "fixtures", filename)
|
19
|
+
end
|
20
|
+
|
17
21
|
# Recording response is as simple as writing in terminal:
|
18
22
|
# curl -is -H "GData-Version: 2" "https://picasaweb.google.com/data/feed/api/user/username?prettyprint=true" -X GET > test/fixtures/albums.txt
|
19
23
|
def fixture(filename)
|
@@ -20,6 +20,10 @@ describe Picasa::Presenter::Album do
|
|
20
20
|
assert_equal 3, @album.links.size
|
21
21
|
end
|
22
22
|
|
23
|
+
it "has etag" do
|
24
|
+
assert_equal "\"YDkqeyI.\"", @album.etag
|
25
|
+
end
|
26
|
+
|
23
27
|
it "has media credit" do
|
24
28
|
assert_equal "Wojciech Wnętrzak", @album.media.credit
|
25
29
|
end
|
@@ -127,6 +131,10 @@ describe Picasa::Presenter::Album do
|
|
127
131
|
assert_equal "5243667126168669553", @album.id
|
128
132
|
end
|
129
133
|
|
134
|
+
it "has etag" do
|
135
|
+
assert_equal "W/\"DUICQX0_fSp7ImA9WhdSGEo.\"", @album.etag
|
136
|
+
end
|
137
|
+
|
130
138
|
it "has name" do
|
131
139
|
assert_equal "Test2", @album.name
|
132
140
|
end
|
@@ -158,6 +166,14 @@ describe Picasa::Presenter::Album do
|
|
158
166
|
it "has photo entries" do
|
159
167
|
assert_equal 3, @album.entries.size
|
160
168
|
end
|
169
|
+
|
170
|
+
it "has allow_prints" do
|
171
|
+
assert_equal true, @album.allow_prints
|
172
|
+
end
|
173
|
+
|
174
|
+
it "has allow_downloads" do
|
175
|
+
assert_equal true, @album.allow_downloads
|
176
|
+
end
|
161
177
|
end
|
162
178
|
|
163
179
|
describe "album from show with single photo" do
|
data/test/presenter/tag_test.rb
CHANGED
@@ -24,6 +24,10 @@ describe Picasa::Presenter::Tag do
|
|
24
24
|
assert_equal "2012-08-17T08:40:24+00:00", @tag.updated.to_s
|
25
25
|
end
|
26
26
|
|
27
|
+
it "has etag" do
|
28
|
+
assert_equal "W/\"CE8GRXczfip7ImA9WhJWEUQ.\"", @tag.etag
|
29
|
+
end
|
30
|
+
|
27
31
|
it "has title" do
|
28
32
|
assert_equal "nice", @tag.title
|
29
33
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
describe Picasa::Template do
|
4
|
+
it "has name" do
|
5
|
+
template = Picasa::Template.new(:new_album, {})
|
6
|
+
assert_equal :new_album, template.name
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has params" do
|
10
|
+
template = Picasa::Template.new(:new_album, {:title => "My album"})
|
11
|
+
assert_equal({:title => "My album"}, template.params)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "new_album" do
|
15
|
+
it "renders title" do
|
16
|
+
template = Picasa::Template.new(:new_album, {:title => "My album"})
|
17
|
+
assert_match %q{<title type="text">My album</title>}, template.render
|
18
|
+
end
|
19
|
+
|
20
|
+
it "renders summary" do
|
21
|
+
template = Picasa::Template.new(:new_album, {:summary => "My summary"})
|
22
|
+
assert_match %q{<summary type="text">My summary</summary>}, template.render
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: picasa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_xml
|
@@ -72,12 +72,16 @@ files:
|
|
72
72
|
- LICENSE
|
73
73
|
- README.md
|
74
74
|
- Rakefile
|
75
|
+
- extra/Thorfile
|
75
76
|
- lib/picasa.rb
|
76
77
|
- lib/picasa/api/album.rb
|
78
|
+
- lib/picasa/api/base.rb
|
79
|
+
- lib/picasa/api/photo.rb
|
77
80
|
- lib/picasa/api/tag.rb
|
78
81
|
- lib/picasa/client.rb
|
79
82
|
- lib/picasa/connection.rb
|
80
83
|
- lib/picasa/exceptions.rb
|
84
|
+
- lib/picasa/file.rb
|
81
85
|
- lib/picasa/presenter/album.rb
|
82
86
|
- lib/picasa/presenter/album_list.rb
|
83
87
|
- lib/picasa/presenter/author.rb
|
@@ -89,23 +93,32 @@ files:
|
|
89
93
|
- lib/picasa/presenter/tag.rb
|
90
94
|
- lib/picasa/presenter/tag_list.rb
|
91
95
|
- lib/picasa/presenter/thumbnail.rb
|
96
|
+
- lib/picasa/template.rb
|
97
|
+
- lib/picasa/templates/new_album.xml.erb
|
98
|
+
- lib/picasa/templates/new_photo.xml.erb
|
92
99
|
- lib/picasa/utils.rb
|
93
100
|
- lib/picasa/version.rb
|
94
101
|
- picasa.gemspec
|
95
102
|
- test/api/album_test.rb
|
103
|
+
- test/api/photo_test.rb
|
96
104
|
- test/api/tag_test.rb
|
97
105
|
- test/client_test.rb
|
98
106
|
- test/connection_test.rb
|
107
|
+
- test/file_test.rb
|
108
|
+
- test/fixtures/album/album-create.txt
|
99
109
|
- test/fixtures/album/album-list-with-tag.txt
|
100
110
|
- test/fixtures/album/album-list.txt
|
101
111
|
- test/fixtures/album/album-show-with-max-results.txt
|
102
112
|
- test/fixtures/album/album-show-with-tag-and-many-photos.txt
|
103
113
|
- test/fixtures/album/album-show-with-tag-and-one-photo.txt
|
104
114
|
- test/fixtures/album/album-show.txt
|
105
|
-
- test/fixtures/auth/failure.txt
|
106
115
|
- test/fixtures/auth/success.txt
|
116
|
+
- test/fixtures/exceptions/forbidden.txt
|
117
|
+
- test/fixtures/exceptions/not_found.txt
|
118
|
+
- test/fixtures/exceptions/precondition_failed.txt
|
107
119
|
- test/fixtures/json.txt
|
108
|
-
- test/fixtures/
|
120
|
+
- test/fixtures/lena.jpg
|
121
|
+
- test/fixtures/photo/photo-created.txt
|
109
122
|
- test/fixtures/photo/photo-list-all-with-q.txt
|
110
123
|
- test/fixtures/photo/photo-list-all.txt
|
111
124
|
- test/fixtures/photo/photo-list-user.txt
|
@@ -126,6 +139,7 @@ files:
|
|
126
139
|
- test/presenter/tag_list_test.rb
|
127
140
|
- test/presenter/tag_test.rb
|
128
141
|
- test/presenter/thumbnail_test.rb
|
142
|
+
- test/template_test.rb
|
129
143
|
- test/utils_test.rb
|
130
144
|
homepage: https://github.com/morgoth/picasa
|
131
145
|
licenses: []
|