goodreads 0.6.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/LICENSE +2 -2
- data/README.md +21 -3
- data/goodreads.gemspec +2 -2
- data/lib/goodreads/client.rb +11 -2
- data/lib/goodreads/client/authors.rb +8 -0
- data/lib/goodreads/client/friends.rb +2 -2
- data/lib/goodreads/client/reviews.rb +56 -0
- data/lib/goodreads/client/shelves.rb +68 -0
- data/lib/goodreads/errors.rb +2 -0
- data/lib/goodreads/request.rb +41 -6
- data/lib/goodreads/version.rb +1 -1
- data/spec/authentication_spec.rb +24 -11
- data/spec/client_spec.rb +202 -1
- data/spec/fixtures/author_books.xml +1338 -0
- data/spec/fixtures/review_create.xml +102 -0
- data/spec/fixtures/review_show_by_user_and_book.xml +144 -0
- data/spec/fixtures/review_update.xml +104 -0
- data/spec/fixtures/shelf_add_to_shelf.xml +24 -0
- data/spec/fixtures/shelf_list.xml +51 -0
- data/spec/goodreads_spec.rb +1 -1
- metadata +28 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 328c7dcd4de9aaf162c5dba7982e50451abfe96ca12d078367a9dd0293b5d6da
|
4
|
+
data.tar.gz: 413ab442ee0b50901b3e519e1d3cbd3bda0f18d04e28fb98ae65676b73399696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74594d009980dedd882344a3674da6bc5393ad399861b1cd1a0a1a59e112586c15975be0d2f691debf287074795e0e52e00035aac44575bbd1b710842e69c794
|
7
|
+
data.tar.gz: e355ba7c55d71f9fb1b3ac62b549eba718468f1cab8e8b8a2c922401da594c63927c9b060f305ad2c16439cbb1ba24684a866dcd486133f2d0d13969d94bd960
|
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2011-
|
3
|
+
Copyright (c) 2011-2020 Dan Sosedoff <dan.sosedoff@gmail.com>
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
6
|
this software and associated documentation files (the "Software"), to deal in
|
@@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
17
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
18
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
19
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Ruby wrapper to communicate with Goodreads API.
|
4
4
|
|
5
|
+
**NOTE: The Goodreads API [is being discontinued](https://www.goodreads.com/api).**
|
6
|
+
|
5
7
|
## Requirements
|
6
8
|
|
7
9
|
- Ruby 1.9.3+
|
@@ -110,6 +112,17 @@ author.name # => author name
|
|
110
112
|
author.link # => link to author's Goodreads page
|
111
113
|
```
|
112
114
|
|
115
|
+
Look up books by an author:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
author = client.author_Book("id")
|
119
|
+
|
120
|
+
author.id # => author id
|
121
|
+
author.name # => author name
|
122
|
+
author.link # => link to author's Goodreads page
|
123
|
+
author.books # => array of books by this author
|
124
|
+
```
|
125
|
+
|
113
126
|
### Reviews
|
114
127
|
|
115
128
|
Pull recent reviews:
|
@@ -170,7 +183,6 @@ group_list.total # => total number of groups
|
|
170
183
|
group_list.group.count # => number of groups returned in the request
|
171
184
|
|
172
185
|
# Loop through the list to get details for each of the groups.
|
173
|
-
|
174
186
|
group_list.group.each do |g|
|
175
187
|
g.id # => group id
|
176
188
|
g.access # => access settings (private, public)
|
@@ -184,6 +196,14 @@ end
|
|
184
196
|
The `sort` parameter is optional, and defaults to `my_activity`.
|
185
197
|
For other sorting options, [see here](http://www.goodreads.com/api#group.list).
|
186
198
|
|
199
|
+
### Pagination
|
200
|
+
|
201
|
+
To retrieve results for a particular page use the `page` param when making calls:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
books = client.search_books("Term", page: 2)
|
205
|
+
```
|
206
|
+
|
187
207
|
### OAuth
|
188
208
|
|
189
209
|
For API calls requiring permission, such as write operations or browsing friends,
|
@@ -209,5 +229,3 @@ You're welcome to submit patches and new features.
|
|
209
229
|
## License
|
210
230
|
|
211
231
|
The MIT License (MIT)
|
212
|
-
|
213
|
-
Copyright (c) 2011-2015 Dan Sosedoff, <dan.sosedoff@gmail.com>
|
data/goodreads.gemspec
CHANGED
@@ -17,9 +17,9 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.add_development_dependency "yard", "~> 0.9"
|
18
18
|
|
19
19
|
spec.add_runtime_dependency "rest-client", "~> 2.0"
|
20
|
-
spec.add_runtime_dependency "hashie", "~>
|
20
|
+
spec.add_runtime_dependency "hashie", "~> 4.1.0"
|
21
21
|
spec.add_runtime_dependency "activesupport", ">= 3.0"
|
22
|
-
spec.add_runtime_dependency "i18n", "
|
22
|
+
spec.add_runtime_dependency "i18n", ">= 0.6", "< 2"
|
23
23
|
spec.add_runtime_dependency "oauth", "~> 0.4"
|
24
24
|
|
25
25
|
spec.files = `git ls-files`.split("\n")
|
data/lib/goodreads/client.rb
CHANGED
@@ -31,9 +31,18 @@ module Goodreads
|
|
31
31
|
def initialize(options = {})
|
32
32
|
fail(ArgumentError, "Options hash required.") unless options.is_a?(Hash)
|
33
33
|
|
34
|
-
@api_key
|
35
|
-
@api_secret
|
34
|
+
@api_key = options[:api_key] || Goodreads.configuration[:api_key]
|
35
|
+
@api_secret = options[:api_secret] || Goodreads.configuration[:api_secret]
|
36
36
|
@oauth_token = options[:oauth_token]
|
37
37
|
end
|
38
|
+
|
39
|
+
# Return if this client is configured with OAuth credentials
|
40
|
+
# for a single user
|
41
|
+
#
|
42
|
+
# False when client is instantiated with an api_key and secret,
|
43
|
+
# true when client is instantiated with an oauth_token
|
44
|
+
def oauth_configured?
|
45
|
+
!oauth_token.nil?
|
46
|
+
end
|
38
47
|
end
|
39
48
|
end
|
@@ -8,6 +8,14 @@ module Goodreads
|
|
8
8
|
Hashie::Mash.new(data["author"])
|
9
9
|
end
|
10
10
|
|
11
|
+
# Get an author's books
|
12
|
+
#
|
13
|
+
def author_books(id, params = {})
|
14
|
+
params[:id] = id
|
15
|
+
data = request("/author/list", params)
|
16
|
+
Hashie::Mash.new(data["author"])
|
17
|
+
end
|
18
|
+
|
11
19
|
# Search for an author by name
|
12
20
|
#
|
13
21
|
def author_by_name(name, params = {})
|
@@ -4,8 +4,8 @@ module Goodreads
|
|
4
4
|
#
|
5
5
|
# user_id - integer or string
|
6
6
|
#
|
7
|
-
def friends(user_id)
|
8
|
-
data = oauth_request("/friend/user/#{user_id}")
|
7
|
+
def friends(user_id, options={})
|
8
|
+
data = oauth_request("/friend/user/#{user_id}", options)
|
9
9
|
Hashie::Mash.new(data["friends"])
|
10
10
|
end
|
11
11
|
end
|
@@ -31,5 +31,61 @@ module Goodreads
|
|
31
31
|
[]
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
# Get a user's review for a given book
|
36
|
+
def user_review(user_id, book_id, params = {})
|
37
|
+
data = request('/review/show_by_user_and_book.xml', params.merge(v: "2", user_id: user_id, book_id: book_id))
|
38
|
+
Hashie::Mash.new(data["review"])
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add review for a book
|
42
|
+
#
|
43
|
+
# Params can include :review, :rating, and :shelf
|
44
|
+
#
|
45
|
+
# review: text of the review (optional)
|
46
|
+
# rating: rating (0-5) (optional, default is 0 (no rating))
|
47
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
48
|
+
#
|
49
|
+
# Note that Goodreads API documentation says that this endpoint accepts
|
50
|
+
# the read_at parameter but it does not appear to work as of 2018-06.
|
51
|
+
def create_review(book_id, params = {})
|
52
|
+
params = params.merge(book_id: book_id, v: "2")
|
53
|
+
|
54
|
+
params[:read_at] = params[:read_at].strftime('%Y-%m-%d') if params[:read_at].is_a?(Time)
|
55
|
+
|
56
|
+
params[:'review[review]'] = params.delete(:review) if params[:review]
|
57
|
+
params[:'review[rating]'] = params.delete(:rating) if params[:rating]
|
58
|
+
params[:'review[read_at]'] = params.delete(:read_at) if params[:read_at]
|
59
|
+
|
60
|
+
data = oauth_request_method(:post, '/review.xml', params)
|
61
|
+
|
62
|
+
Hashie::Mash.new(data["review"])
|
63
|
+
end
|
64
|
+
|
65
|
+
# Edit review for a book
|
66
|
+
#
|
67
|
+
# Params can include :review, :rating, :read_at and :shelf, and :finished
|
68
|
+
#
|
69
|
+
# review: text of the review (optional)
|
70
|
+
# rating: rating (0-5) (optional, default is 0 (no rating))
|
71
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
72
|
+
# read_at: Time object or String in YYYY-MM-DD format (optional)
|
73
|
+
# finished: true to mark finished reading (optional)
|
74
|
+
# shelf: Name of shelf to add book to (optional, must exist, see: shelves.list)
|
75
|
+
def edit_review(review_id, params = {})
|
76
|
+
params = params.merge(v: "2")
|
77
|
+
|
78
|
+
params[:read_at] = params[:read_at].strftime('%Y-%m-%d') if params[:read_at].is_a?(Time)
|
79
|
+
|
80
|
+
params[:'review[review]'] = params.delete(:review) if params[:review]
|
81
|
+
params[:'review[rating]'] = params.delete(:rating) if params[:rating]
|
82
|
+
params[:'review[read_at]'] = params.delete(:read_at) if params[:read_at]
|
83
|
+
|
84
|
+
# Documentation says that you should use HTTP PUT, but API returns
|
85
|
+
# 401 Unauthorized when PUT is used instead of POST
|
86
|
+
data = oauth_request_method(:post, "/review/#{review_id}.xml", params)
|
87
|
+
|
88
|
+
Hashie::Mash.new(data["review"])
|
89
|
+
end
|
34
90
|
end
|
35
91
|
end
|
@@ -1,5 +1,36 @@
|
|
1
1
|
module Goodreads
|
2
2
|
module Shelves
|
3
|
+
# Lists shelves for a user
|
4
|
+
def shelves(user_id, options = {})
|
5
|
+
options = options.merge(user_id: user_id, v: 2)
|
6
|
+
data = request("/shelf/list.xml", options)
|
7
|
+
shelves = data["shelves"]
|
8
|
+
|
9
|
+
shelves = data["shelves"]["user_shelf"].map do |s|
|
10
|
+
Hashie::Mash.new({
|
11
|
+
id: s["id"],
|
12
|
+
name: s["name"],
|
13
|
+
book_count: s["book_count"],
|
14
|
+
exclusive: s["exclusive_flag"],
|
15
|
+
description: s["description"],
|
16
|
+
sort: s["sort"],
|
17
|
+
order: s["order"],
|
18
|
+
per_page: s["per_page"],
|
19
|
+
display_fields: s["display_fields"],
|
20
|
+
featured: s["featured"],
|
21
|
+
recommend_for: s["recommend_for"],
|
22
|
+
sticky: s["sticky"],
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
Hashie::Mash.new(
|
27
|
+
start: data["shelves"]["start"].to_i,
|
28
|
+
end: data["shelves"]["end"].to_i,
|
29
|
+
total: data["shelves"]["total"].to_i,
|
30
|
+
shelves: shelves
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
3
34
|
# Get books from a user's shelf
|
4
35
|
def shelf(user_id, shelf_name, options = {})
|
5
36
|
options = options.merge(shelf: shelf_name, v: 2)
|
@@ -20,5 +51,42 @@ module Goodreads
|
|
20
51
|
books: books
|
21
52
|
)
|
22
53
|
end
|
54
|
+
|
55
|
+
# Add book to a user's shelf
|
56
|
+
#
|
57
|
+
# Returns the user's review for the book, which includes all its current shelves
|
58
|
+
def add_to_shelf(book_id, shelf_name, options = {})
|
59
|
+
options = options.merge(book_id: book_id, name: shelf_name, v: 2)
|
60
|
+
data = oauth_request_method(:post, "/shelf/add_to_shelf.xml", options)
|
61
|
+
|
62
|
+
# when a book is on a single shelf it is a single hash
|
63
|
+
shelves = data["my_review"]["shelves"]["shelf"]
|
64
|
+
shelves = [shelves] unless shelves.instance_of?(Array)
|
65
|
+
shelves = shelves.map do |s|
|
66
|
+
Hashie::Mash.new({
|
67
|
+
id: s["id"].to_i,
|
68
|
+
name: s["name"],
|
69
|
+
exclusive: s["exclusive"] == "true",
|
70
|
+
sortable: s["sortable"] == "true",
|
71
|
+
})
|
72
|
+
end
|
73
|
+
|
74
|
+
Hashie::Mash.new(
|
75
|
+
id: data["my_review"]["id"].to_i,
|
76
|
+
book_id: data["my_review"]["book_id"].to_i,
|
77
|
+
|
78
|
+
rating: data["my_review"]["rating"].to_i,
|
79
|
+
body: data["my_review"]["body"],
|
80
|
+
body_raw: data["my_review"]["body_raw"],
|
81
|
+
spoiler: data["my_review"]["spoiler_flag"] == "true",
|
82
|
+
|
83
|
+
shelves: shelves,
|
84
|
+
|
85
|
+
read_at: data["my_review"]["read_at"],
|
86
|
+
started_at: data["my_review"]["started_at"],
|
87
|
+
date_added: data["my_review"]["date_added"],
|
88
|
+
updated_at: data["my_review"]["updated_at"],
|
89
|
+
)
|
90
|
+
end
|
23
91
|
end
|
24
92
|
end
|
data/lib/goodreads/errors.rb
CHANGED
data/lib/goodreads/request.rb
CHANGED
@@ -9,12 +9,26 @@ module Goodreads
|
|
9
9
|
|
10
10
|
protected
|
11
11
|
|
12
|
-
# Perform an API request
|
12
|
+
# Perform an API request using API key or OAuth token
|
13
13
|
#
|
14
14
|
# path - Request path
|
15
15
|
# params - Parameters hash
|
16
16
|
#
|
17
|
+
# Will make a request with the configured API key (application
|
18
|
+
# authentication) or OAuth token (user authentication) if available.
|
17
19
|
def request(path, params = {})
|
20
|
+
if oauth_configured?
|
21
|
+
oauth_request(path, params)
|
22
|
+
else
|
23
|
+
http_request(path, params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Perform an API request using API key
|
28
|
+
#
|
29
|
+
# path - Request path
|
30
|
+
# params - Parameters hash
|
31
|
+
def http_request(path, params)
|
18
32
|
token = api_key || Goodreads.configuration[:api_key]
|
19
33
|
|
20
34
|
fail(Goodreads::ConfigurationError, "API key required.") if token.nil?
|
@@ -32,24 +46,45 @@ module Goodreads
|
|
32
46
|
fail(Goodreads::Forbidden)
|
33
47
|
when 404
|
34
48
|
fail(Goodreads::NotFound)
|
49
|
+
when 500..599
|
50
|
+
fail(Goodreads::ServerError.new(response.code))
|
51
|
+
else
|
52
|
+
fail(Goodreads::UnknownError.new(response.code))
|
35
53
|
end
|
36
54
|
end
|
37
55
|
|
38
56
|
parse(resp)
|
39
57
|
end
|
40
58
|
|
59
|
+
# Perform an OAuth API GET request. Goodreads must have been initialized with a valid OAuth access token.
|
60
|
+
#
|
61
|
+
# path - Request path
|
62
|
+
# params - Parameters hash
|
63
|
+
#
|
64
|
+
def oauth_request(path, params = {})
|
65
|
+
oauth_request_method(:get, path, params)
|
66
|
+
end
|
67
|
+
|
41
68
|
# Perform an OAuth API request. Goodreads must have been initialized with a valid OAuth access token.
|
42
69
|
#
|
70
|
+
# http_method - HTTP verb supported by OAuth gem (one of :get, :post, :delete, etc.)
|
43
71
|
# path - Request path
|
44
72
|
# params - Parameters hash
|
45
73
|
#
|
46
|
-
def
|
74
|
+
def oauth_request_method(http_method, path, params = {})
|
47
75
|
fail "OAuth access token required!" unless @oauth_token
|
48
|
-
|
49
|
-
|
50
|
-
|
76
|
+
|
77
|
+
headers = { "Accept" => "application/xml" }
|
78
|
+
|
79
|
+
resp = if http_method == :get || http_method == :delete
|
80
|
+
if params
|
81
|
+
url_params = params.map { |k, v| "#{k}=#{v}" }.join("&")
|
82
|
+
path = "#{path}?#{url_params}"
|
83
|
+
end
|
84
|
+
@oauth_token.request(http_method, path, headers)
|
85
|
+
else
|
86
|
+
@oauth_token.request(http_method, path, params || {}, headers)
|
51
87
|
end
|
52
|
-
resp = @oauth_token.get(path, "Accept" => "application/xml")
|
53
88
|
|
54
89
|
case resp
|
55
90
|
when Net::HTTPUnauthorized
|
data/lib/goodreads/version.rb
CHANGED
data/spec/authentication_spec.rb
CHANGED
@@ -1,24 +1,37 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Goodreads::Client do
|
4
4
|
before :each do
|
5
5
|
Goodreads.reset_configuration
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
let(:client) do
|
9
|
+
described_class.new(api_key: api_key)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "API key is missing" do
|
13
|
+
let(:api_key) {}
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
it "throws an error" do
|
16
|
+
expect { client.book_by_isbn("0307463745") }
|
17
|
+
.to raise_error(Goodreads::ConfigurationError, "API key required.")
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
|
-
|
16
|
-
|
21
|
+
context "API key is invalid" do
|
22
|
+
let(:api_key) { "INVALID_KEY" }
|
23
|
+
|
24
|
+
before do
|
25
|
+
stub_request(:get, "https://www.goodreads.com/book/isbn?format=xml&isbn=1&key=INVALID_KEY")
|
26
|
+
.to_return(status: 401)
|
17
27
|
|
18
|
-
|
19
|
-
|
28
|
+
stub_request(:get, "https://www.goodreads.com/book/isbn?format=xml&isbn=2&key=INVALID_KEY")
|
29
|
+
.to_return(status: 403)
|
30
|
+
end
|
20
31
|
|
21
|
-
|
22
|
-
.to raise_error(Goodreads::Unauthorized)
|
32
|
+
it "throws errors" do
|
33
|
+
expect { client.book_by_isbn("1") }.to raise_error(Goodreads::Unauthorized)
|
34
|
+
expect { client.book_by_isbn("2") }.to raise_error(Goodreads::Forbidden)
|
35
|
+
end
|
23
36
|
end
|
24
37
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "oauth"
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe Goodreads::Client do
|
5
5
|
let(:client) { Goodreads::Client.new(api_key: "SECRET_KEY") }
|
6
6
|
before(:each) { Goodreads.reset_configuration }
|
7
7
|
|
@@ -17,6 +17,45 @@ describe "Client" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
describe "#oauth_configured?" do
|
21
|
+
it "is true when OAuth token provided to constructor" do
|
22
|
+
client = Goodreads::Client.new(oauth_token: "a token")
|
23
|
+
expect(client.oauth_configured?).to be true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is true when oauth token is not provided to constructor" do
|
27
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY")
|
28
|
+
expect(client.oauth_configured?).to be false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#request" do
|
33
|
+
context "with oauth token" do
|
34
|
+
it "makes an oauth request" do
|
35
|
+
oauth_token = double
|
36
|
+
response = double
|
37
|
+
|
38
|
+
allow(oauth_token).to receive(:request) { response }
|
39
|
+
allow(response).to receive(:body) { fixture("book.xml") }
|
40
|
+
|
41
|
+
client = Goodreads::Client.new(oauth_token: oauth_token)
|
42
|
+
expect(client.book(123)).to be_a Hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "without oauth token" do
|
47
|
+
before do
|
48
|
+
allow(client).to receive(:http_request) {
|
49
|
+
Hash.from_xml(fixture("book.xml"))["GoodreadsResponse"]
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
it "makes a request" do
|
54
|
+
expect(client.book(123)).to be_a Hash
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
20
59
|
describe "#book_by_isbn" do
|
21
60
|
before { stub_with_key_get("/book/isbn", { isbn: "0307463745" }, "book.xml") }
|
22
61
|
|
@@ -154,6 +193,26 @@ describe "Client" do
|
|
154
193
|
end
|
155
194
|
end
|
156
195
|
|
196
|
+
describe "#user_review" do
|
197
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
198
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
199
|
+
|
200
|
+
it "returns a user's existing review" do
|
201
|
+
stub_request(:get, "https://www.goodreads.com/review/show_by_user_and_book.xml?book_id=50&user_id=1&v=2")
|
202
|
+
.to_return(status: 200, body: fixture("review_show_by_user_and_book.xml"))
|
203
|
+
|
204
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
205
|
+
review = client.user_review(1, 50)
|
206
|
+
|
207
|
+
expect(review.id).to eq("21")
|
208
|
+
expect(review.book.id).to eq(50)
|
209
|
+
|
210
|
+
expect(review.rating).to eq("5")
|
211
|
+
expect(review.body.strip).to eq("")
|
212
|
+
expect(review.date_added).to eq("Tue Aug 29 11:20:01 -0700 2006")
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
157
216
|
describe "#author" do
|
158
217
|
before { stub_with_key_get("/author/show", { id: "18541" }, "author.xml") }
|
159
218
|
|
@@ -203,6 +262,23 @@ describe "Client" do
|
|
203
262
|
end
|
204
263
|
end
|
205
264
|
|
265
|
+
describe "#author_books" do
|
266
|
+
before do
|
267
|
+
stub_with_key_get("/author/list", { id: "18541" }, "author_books.xml")
|
268
|
+
end
|
269
|
+
|
270
|
+
it "returns author's books" do
|
271
|
+
author = client.author_books("18541")
|
272
|
+
|
273
|
+
expect(author).to be_a(Hashie::Mash)
|
274
|
+
expect(author.id).to eq("18541")
|
275
|
+
expect(author.name).to eq("Tim O'Reilly")
|
276
|
+
expect(author.link).to eq("https://www.goodreads.com/author/show/18541.Tim_O_Reilly")
|
277
|
+
|
278
|
+
expect(author.books.book.size).to eq(30)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
206
282
|
describe "#user" do
|
207
283
|
before { stub_with_key_get("/user/show", { id: "878044" }, "user.xml") }
|
208
284
|
|
@@ -287,6 +363,131 @@ describe "Client" do
|
|
287
363
|
end
|
288
364
|
end
|
289
365
|
|
366
|
+
describe "#add_to_shelf" do
|
367
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
368
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
369
|
+
|
370
|
+
it "adds a book to a user's shelf" do
|
371
|
+
stub_request(:post, "https://www.goodreads.com/shelf/add_to_shelf.xml")
|
372
|
+
.with(:body => {"book_id"=>"456", "name"=>"read", "v"=>"2"})
|
373
|
+
.to_return(status: 201, body: fixture("shelf_add_to_shelf.xml"))
|
374
|
+
|
375
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
376
|
+
review = client.add_to_shelf(456, "read")
|
377
|
+
|
378
|
+
expect(review.id).to eq(2416981504)
|
379
|
+
expect(review.book_id).to eq(456)
|
380
|
+
|
381
|
+
expect(review.rating).to eq(0)
|
382
|
+
expect(review.body).to be nil
|
383
|
+
expect(review.body_raw).to be nil
|
384
|
+
expect(review.spoiler).to be false
|
385
|
+
|
386
|
+
expect(review.shelves.size).to eq(1)
|
387
|
+
expect(review.shelves.first.name).to eq("read")
|
388
|
+
expect(review.shelves.first.id).to eq(269274694)
|
389
|
+
expect(review.shelves.first.exclusive).to be true
|
390
|
+
expect(review.shelves.first.sortable).to be false
|
391
|
+
|
392
|
+
|
393
|
+
expect(review.read_at).to be nil
|
394
|
+
expect(review.started_at).to be nil
|
395
|
+
expect(review.date_added).to eq("Thu Jun 07 19:58:19 -0700 2018")
|
396
|
+
expect(review.updated_at).to eq("Thu Jun 07 19:58:53 -0700 2018")
|
397
|
+
|
398
|
+
expect(review.body).to be nil
|
399
|
+
expect(review.body_raw).to be nil
|
400
|
+
expect(review.spoiler).to be false
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
describe "#create_review" do
|
405
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
406
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
407
|
+
|
408
|
+
it "creates a new review for a book" do
|
409
|
+
stub_request(:post, "https://www.goodreads.com/review.xml")
|
410
|
+
.with(:body => {
|
411
|
+
"book_id"=>"456",
|
412
|
+
"review" => {
|
413
|
+
"rating" => "3",
|
414
|
+
"review" => "Good book.",
|
415
|
+
"read_at" => "2018-01-02",
|
416
|
+
},
|
417
|
+
"shelf" => "read",
|
418
|
+
"v"=>"2",
|
419
|
+
})
|
420
|
+
.to_return(status: 201, body: fixture("review_create.xml"))
|
421
|
+
|
422
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
423
|
+
review = client.create_review(456, {
|
424
|
+
:review => "Good book.",
|
425
|
+
:rating => 3,
|
426
|
+
:read_at => Time.parse('2018-01-02'),
|
427
|
+
:shelf => "read",
|
428
|
+
})
|
429
|
+
|
430
|
+
expect(review.id).to eq("67890")
|
431
|
+
expect(review.book.id).to eq(456)
|
432
|
+
expect(review.rating).to eq("3")
|
433
|
+
expect(review.body).to eq("Good book.")
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
describe "#edit_review" do
|
438
|
+
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
439
|
+
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|
440
|
+
|
441
|
+
it "creates a new review for a book" do
|
442
|
+
stub_request(:post, "https://www.goodreads.com/review/67890.xml")
|
443
|
+
.with(:body => {
|
444
|
+
"finished" => "true",
|
445
|
+
"review" => {
|
446
|
+
"rating" => "5",
|
447
|
+
"review" => "Fantastic book.",
|
448
|
+
"read_at" => "2018-04-15",
|
449
|
+
},
|
450
|
+
"shelf" => "read",
|
451
|
+
"v"=>"2",
|
452
|
+
})
|
453
|
+
.to_return(status: 201, body: fixture("review_update.xml"))
|
454
|
+
|
455
|
+
client = Goodreads::Client.new(api_key: "SECRET_KEY", oauth_token: token)
|
456
|
+
review = client.edit_review(67890, {
|
457
|
+
:finished => true,
|
458
|
+
:review => "Fantastic book.",
|
459
|
+
:rating => 5,
|
460
|
+
:read_at => Time.parse('2018-04-15'),
|
461
|
+
:shelf => "read",
|
462
|
+
})
|
463
|
+
|
464
|
+
expect(review.id).to eq("67890")
|
465
|
+
expect(review.book.id).to eq(456)
|
466
|
+
expect(review.rating).to eq("5")
|
467
|
+
expect(review.body).to eq("Fantastic book.")
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
describe "#shelves" do
|
472
|
+
it "returns list of user's shelves" do
|
473
|
+
stub_with_key_get("/shelf/list.xml", { user_id: 123, v: "2" }, "shelf_list.xml")
|
474
|
+
|
475
|
+
response = client.shelves(123)
|
476
|
+
|
477
|
+
expect(response).to respond_to(:start)
|
478
|
+
expect(response).to respond_to(:end)
|
479
|
+
expect(response).to respond_to(:total)
|
480
|
+
expect(response).to respond_to(:shelves)
|
481
|
+
|
482
|
+
expect(response.start).to eq(1)
|
483
|
+
expect(response.end).to eq(3)
|
484
|
+
expect(response.total).to eq(3)
|
485
|
+
expect(response.shelves.length).to eq(3)
|
486
|
+
expect(response.shelves.first.id).to eq(9049904)
|
487
|
+
expect(response.shelves.first.name).to eq("read")
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
290
491
|
describe "#user_id" do
|
291
492
|
let(:consumer) { OAuth::Consumer.new("API_KEY", "SECRET_KEY", site: "https://www.goodreads.com") }
|
292
493
|
let(:token) { OAuth::AccessToken.new(consumer, "ACCESS_TOKEN", "ACCESS_SECRET") }
|