goodreads 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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") }
|