pinterest-ruby 1.0.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 +7 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +63 -0
- data/.travis-gemfile +17 -0
- data/.travis.yml +12 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +24 -0
- data/README.md +34 -0
- data/Rakefile +44 -0
- data/docs/FaradayMiddleware/SafeOj.html +218 -0
- data/docs/FaradayMiddleware.html +125 -0
- data/docs/Pinterest/Board.html +410 -0
- data/docs/Pinterest/Client.html +1894 -0
- data/docs/Pinterest/Collection.html +1877 -0
- data/docs/Pinterest/Endpoints/Authentication.html +578 -0
- data/docs/Pinterest/Endpoints/Boards.html +1443 -0
- data/docs/Pinterest/Endpoints/Pins.html +1296 -0
- data/docs/Pinterest/Endpoints/Users.html +1220 -0
- data/docs/Pinterest/Endpoints.html +127 -0
- data/docs/Pinterest/Entity.html +473 -0
- data/docs/Pinterest/Errors/AuthorizationError.html +158 -0
- data/docs/Pinterest/Errors/BadRequestError.html +158 -0
- data/docs/Pinterest/Errors/BaseError.html +487 -0
- data/docs/Pinterest/Errors/MethodNotAllowedError.html +158 -0
- data/docs/Pinterest/Errors/NotFoundError.html +158 -0
- data/docs/Pinterest/Errors/NotImplementedError.html +158 -0
- data/docs/Pinterest/Errors/PermissionsError.html +158 -0
- data/docs/Pinterest/Errors/RateLimitError.html +158 -0
- data/docs/Pinterest/Errors/ServerError.html +158 -0
- data/docs/Pinterest/Errors/TimeoutError.html +158 -0
- data/docs/Pinterest/Errors.html +377 -0
- data/docs/Pinterest/Image.html +617 -0
- data/docs/Pinterest/Interest.html +402 -0
- data/docs/Pinterest/Pin.html +511 -0
- data/docs/Pinterest/User.html +408 -0
- data/docs/Pinterest/Version.html +187 -0
- data/docs/Pinterest.html +130 -0
- data/docs/_index.html +401 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +492 -0
- data/docs/file.README.html +106 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +106 -0
- data/docs/js/app.js +243 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +643 -0
- data/docs/top-level-namespace.html +110 -0
- data/lib/pinterest/client.rb +146 -0
- data/lib/pinterest/collection.rb +97 -0
- data/lib/pinterest/endpoints/authentication.rb +99 -0
- data/lib/pinterest/endpoints/boards.rb +193 -0
- data/lib/pinterest/endpoints/pins.rb +187 -0
- data/lib/pinterest/endpoints/users.rb +158 -0
- data/lib/pinterest/errors.rb +94 -0
- data/lib/pinterest/models/board.rb +34 -0
- data/lib/pinterest/models/entity.rb +42 -0
- data/lib/pinterest/models/image.rb +49 -0
- data/lib/pinterest/models/interest.rb +30 -0
- data/lib/pinterest/models/pin.rb +43 -0
- data/lib/pinterest/models/user.rb +33 -0
- data/lib/pinterest/safe_oj.rb +25 -0
- data/lib/pinterest/version.rb +23 -0
- data/lib/pinterest.rb +31 -0
- data/pinterest.gemspec +32 -0
- data/spec/cassettes/Pinterest_Client/_perform_network_request_private_/should_correctly_handle_malformed_requests.yml +51 -0
- data/spec/cassettes/Pinterest_Endpoints_Authentication/_fetch_access_token/should_make_the_call_to_Pinterest_and_return_the_authorization_token_also_saving_it.yml +58 -0
- data/spec/cassettes/Pinterest_Endpoints_Authentication/_verify_access_token/should_return_an_exception_when_using_an_invalid_token.yml +52 -0
- data/spec/cassettes/Pinterest_Endpoints_Authentication/_verify_access_token/should_verify_the_token.yml +59 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_complain_for_invalid_boards.yml +48 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_get_the_current_informations.yml +63 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_restrict_to_requested_fields.yml +57 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_boards/should_only_get_requested_fields.yml +57 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_boards/should_return_a_list_of_boards.yml +74 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_create_board/should_create_the_board_and_return_it_with_only_the_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_delete_board/should_perform_the_call_and_return_an_error.yml +48 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_delete_board/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_edit_board/should_edit_the_board_and_return_it_with_only_the_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_follow_board/should_complain_for_invalid_boards.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_follow_board/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_only_get_requested_fields.yml +59 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_paginate_correctly.yml +72 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_return_the_followed_boards.yml +72 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_only_get_requested_fields.yml +59 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_paginate_correctly.yml +66 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_search_boards.yml +75 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_suggested_boards/should_return_the_suggested_boards_returning_only_the_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_unfollow_board/should_complain_for_invalid_boards.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Boards/_unfollow_board/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_only_get_requested_fields.yml +59 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_paginate_correctly.yml +85 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_return_the_pins_of_the_board.yml +85 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_create_a_pin_by_using_a_image_URL.yml +71 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_create_a_pin_by_using_a_image_file.yml +1997 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_return_a_pin_containing_only_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_delete_pin/should_perform_the_call_and_return_an_error.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_delete_pin/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_edit_pin/should_edit_the_pin_and_return_it_with_only_the_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_only_get_requested_fields.yml +58 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_paginate_correctly.yml +87 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_return_the_list_of_liked_pins.yml +85 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_complain_for_non_existent_pins.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_get_the_current_informations.yml +71 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_restrict_to_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_only_get_requested_fields.yml +59 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_paginate_correctly.yml +808 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_return_my_pins.yml +88 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_only_get_requested_fields.yml +61 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_paginate_correctly.yml +89 -0
- data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_search_my_pins.yml +89 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_follow_interest/should_perform_the_call_and_return_an_error.yml +48 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_follow_user/should_complain_for_invalid_users.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_follow_user/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_only_get_requested_fields.yml +62 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_paginate_correctly.yml +62 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_return_a_list_of_followers.yml +62 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_only_get_requested_fields.yml +62 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_paginate_correctly.yml +131 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_return_a_list_of_followed_users.yml +66 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_interests/should_paginate_correctly.yml +112 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_interests/should_return_a_list_of_followed_interest.yml +58 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_me/should_get_the_current_informations.yml +62 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_me/should_restrict_to_requested_fields.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_interest/should_perform_the_call_and_return_an_error.yml +48 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_user/should_complain_for_invalid_users.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_user/should_perform_the_call_and_return_true.yml +109 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_complain_for_non_existent_users.yml +56 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_get_the_current_informations.yml +60 -0
- data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_restrict_to_requested_fields.yml +56 -0
- data/spec/pinterest/client_spec.rb +70 -0
- data/spec/pinterest/collection_spec.rb +82 -0
- data/spec/pinterest/endpoints/authentication_spec.rb +81 -0
- data/spec/pinterest/endpoints/boards_spec.rb +209 -0
- data/spec/pinterest/endpoints/pins_spec.rb +239 -0
- data/spec/pinterest/endpoints/users_spec.rb +194 -0
- data/spec/pinterest/errors_spec.rb +59 -0
- data/spec/pinterest/fixtures/first.jpg +0 -0
- data/spec/pinterest/models/board_spec.rb +48 -0
- data/spec/pinterest/models/entity_spec.rb +35 -0
- data/spec/pinterest/models/image_spec.rb +50 -0
- data/spec/pinterest/models/interest_spec.rb +20 -0
- data/spec/pinterest/models/pin_spec.rb +55 -0
- data/spec/pinterest/models/user_spec.rb +45 -0
- data/spec/spec_helper.rb +49 -0
- data/tester.rb +19 -0
- metadata +341 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.9.7
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
pathId = "";
|
19
|
+
relpath = '';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
24
|
+
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
26
|
+
|
27
|
+
|
28
|
+
</head>
|
29
|
+
<body>
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
38
|
+
|
39
|
+
<a href="_index.html">Index</a> »
|
40
|
+
|
41
|
+
|
42
|
+
<span class="title">Top Level Namespace</span>
|
43
|
+
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div id="search">
|
47
|
+
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
49
|
+
href="class_list.html">
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
56
|
+
</a>
|
57
|
+
|
58
|
+
</div>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
</div>
|
80
|
+
|
81
|
+
<h2>Defined Under Namespace</h2>
|
82
|
+
<p class="children">
|
83
|
+
|
84
|
+
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="FaradayMiddleware.html" title="FaradayMiddleware (module)">FaradayMiddleware</a></span>, <span class='object_link'><a href="Pinterest.html" title="Pinterest (module)">Pinterest</a></span>
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
</p>
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
</div>
|
101
|
+
|
102
|
+
<div id="footer">
|
103
|
+
Generated on Thu Jan 12 16:28:12 2017 by
|
104
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
|
+
0.9.7 (ruby-2.3.0).
|
106
|
+
</div>
|
107
|
+
|
108
|
+
</div>
|
109
|
+
</body>
|
110
|
+
</html>
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of the pinterest-ruby gem. Copyright (C) 2017 and above Shogun <shogun@cowtech.it>.
|
3
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Pinterest
|
7
|
+
# A Pinterest API client.
|
8
|
+
#
|
9
|
+
# @attribute access_token
|
10
|
+
# @return [String] The access token.
|
11
|
+
# @attribute client_id [String]
|
12
|
+
# @return The client id.
|
13
|
+
# @attribute client_secret [String]
|
14
|
+
# @return The client secret.
|
15
|
+
# @attribute verbose [Boolean]
|
16
|
+
# @return If log requests.
|
17
|
+
# @attribute connection_setup [Proc]
|
18
|
+
# @return Additional code to execute on the connection object.
|
19
|
+
class Client
|
20
|
+
# The Pinterest API Root URL.
|
21
|
+
API_URL = "https://api.pinterest.com".freeze
|
22
|
+
|
23
|
+
# The Pinterest API version.
|
24
|
+
API_VERSION = "v1".freeze
|
25
|
+
|
26
|
+
# The allowed authorization scopes.
|
27
|
+
SCOPES = ["read_public", "write_public", "read_relationships", "write_relationships"].freeze
|
28
|
+
|
29
|
+
# The maximum number of results to return by default.
|
30
|
+
DEFAULT_LIMIT = 50
|
31
|
+
|
32
|
+
attr_accessor :client_id, :client_secret, :access_token, :verbose, :connection
|
33
|
+
|
34
|
+
# Creates a new client.
|
35
|
+
#
|
36
|
+
# @param access_token [String] The access token.
|
37
|
+
# @param client_id [String] The client id.
|
38
|
+
# @param client_secret [String] The client secret.
|
39
|
+
# @param verbose [Boolean] If log requests.
|
40
|
+
# @param connection_setup [Proc] Additional code to execute on the connection object.
|
41
|
+
def initialize(access_token: nil, client_id: nil, client_secret: nil, verbose: false, &connection_setup)
|
42
|
+
@client_id = client_id
|
43
|
+
@client_secret = client_secret
|
44
|
+
@access_token = access_token
|
45
|
+
@verbose = verbose
|
46
|
+
|
47
|
+
ensure_connection(connection_setup)
|
48
|
+
end
|
49
|
+
|
50
|
+
include Pinterest::Endpoints::Authentication
|
51
|
+
include Pinterest::Endpoints::Users
|
52
|
+
include Pinterest::Endpoints::Pins
|
53
|
+
include Pinterest::Endpoints::Boards
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# :nodoc:
|
58
|
+
def ensure_connection(setup = nil)
|
59
|
+
setup ||= ->(c) { default_connection_setup(c) }
|
60
|
+
@connection ||= Faraday.new(url: ::Pinterest::Client::API_URL, &setup)
|
61
|
+
end
|
62
|
+
|
63
|
+
# :nodoc:
|
64
|
+
def ensure_array(subject, default = [])
|
65
|
+
subject = (subject ? [subject] : [default]).flatten unless subject.is_a?(Array)
|
66
|
+
subject
|
67
|
+
end
|
68
|
+
|
69
|
+
# :nodoc:
|
70
|
+
def ensure_param(param, error = nil)
|
71
|
+
valid = param && !param.to_s.strip.empty?
|
72
|
+
raise(ArgumentError, error) if error && !valid
|
73
|
+
valid
|
74
|
+
end
|
75
|
+
|
76
|
+
# :nodoc:
|
77
|
+
def default_connection_setup(c)
|
78
|
+
c.request(:multipart)
|
79
|
+
c.request(:url_encoded)
|
80
|
+
c.response(:safe_oj)
|
81
|
+
c.response(:logger) if verbose
|
82
|
+
|
83
|
+
c.use(FaradayMiddleware::FollowRedirects)
|
84
|
+
c.adapter(Faraday.default_adapter)
|
85
|
+
end
|
86
|
+
|
87
|
+
# :nodoc:
|
88
|
+
def cleanup_params(params)
|
89
|
+
params.reject { |_, v| !ensure_param(v) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# :nodoc:
|
93
|
+
# rubocop:disable Metrics/ParameterLists
|
94
|
+
def perform_network_request(method: "GET", url: "/", query: {}, body: {}, headers: {}, authenticated: true, pagination: false, **args, &additional)
|
95
|
+
response = connection.send(method.downcase) do |request|
|
96
|
+
# Setup URL and headers
|
97
|
+
setup_headers(request, url, headers, query, authenticated)
|
98
|
+
|
99
|
+
# Handle pagination
|
100
|
+
handle_pagination(request, args) if pagination
|
101
|
+
|
102
|
+
# Add the body
|
103
|
+
request.body = body
|
104
|
+
|
105
|
+
# Run user callback
|
106
|
+
yield(request) if additional
|
107
|
+
end
|
108
|
+
|
109
|
+
# Perform the call
|
110
|
+
raise(::Pinterest::Errors.create(response)) unless response.success?
|
111
|
+
response
|
112
|
+
rescue Faraday::ParsingError => e
|
113
|
+
handle_network_error(e)
|
114
|
+
end
|
115
|
+
|
116
|
+
# :nodoc:
|
117
|
+
def handle_network_error(e)
|
118
|
+
code = e.response.status
|
119
|
+
message = /<h1>(.+?)<\/h1>/mi.match(e.response.body)
|
120
|
+
|
121
|
+
raise(::Pinterest::Errors.class_for_code(code).new(code, message ? message[1] : "Invalid response from the server.", e.response))
|
122
|
+
end
|
123
|
+
|
124
|
+
# :nodoc:
|
125
|
+
def handle_pagination(request, args)
|
126
|
+
limit = args[:limit].to_i
|
127
|
+
limit = DEFAULT_LIMIT if limit < 1
|
128
|
+
|
129
|
+
request.params[:cursor] = args[:cursor] if args[:cursor]
|
130
|
+
request.params[:limit] = limit
|
131
|
+
end
|
132
|
+
|
133
|
+
# :nodoc:
|
134
|
+
def setup_headers(request, url, headers, query, authenticated)
|
135
|
+
request.url(url)
|
136
|
+
request.headers["Authorization"] = "Bearer #{access_token}" if authenticated
|
137
|
+
request.headers.merge!(headers)
|
138
|
+
request.params.merge!(query)
|
139
|
+
end
|
140
|
+
|
141
|
+
# :nodoc:
|
142
|
+
def versioned_url(url)
|
143
|
+
"/#{::Pinterest::Client::API_VERSION}/#{url.gsub(/^\//, "")}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of the pinterest-ruby gem. Copyright (C) 2017 and above Shogun <shogun@cowtech.it>.
|
3
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Pinterest
|
7
|
+
# A collection of objects, including pagination data.
|
8
|
+
#
|
9
|
+
# @attribute records
|
10
|
+
# @return [Pinterest::Entity] A list of objects.
|
11
|
+
# @attribute limit
|
12
|
+
# @return [Fixnum] The maximum number of results to get from Pinterest API.
|
13
|
+
# @attribute current_cursor
|
14
|
+
# @return [String] The cursor to obtain the current page of results.
|
15
|
+
# @attribute next_cursor
|
16
|
+
# @return [String] The cursor to obtain the next page of results.
|
17
|
+
class Collection
|
18
|
+
attr_reader :records, :limit, :current_cursor, :next_cursor
|
19
|
+
|
20
|
+
# Creates a new collection. This class is for internal use.
|
21
|
+
#
|
22
|
+
# @param raw_data [Hash] A raw response obtained by Pinterest API.
|
23
|
+
# @param cursor [String] The current cursor.
|
24
|
+
# @param limit [Fixnum] The maximum number of records to obtain from Pinterest API.
|
25
|
+
# @param record_creator [Proc] The code to trasform each raw record in a object.
|
26
|
+
def initialize(raw_data, cursor, limit, &record_creator)
|
27
|
+
raise(ArgumentError, "raw_data must be an Hash.") unless raw_data.is_a?(Hash)
|
28
|
+
record_creator ||= ->(record) { record }
|
29
|
+
|
30
|
+
@limit = limit
|
31
|
+
@current_cursor = cursor
|
32
|
+
@next_cursor = raw_data["page"]["cursor"] if raw_data["page"] && raw_data["page"]["cursor"]
|
33
|
+
@records = raw_data.fetch("data", []).map(&record_creator)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns a object from the collection.
|
37
|
+
#
|
38
|
+
# @param index [Fixnum] The index to get.
|
39
|
+
def [](index)
|
40
|
+
records[index]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the size of the collection.
|
44
|
+
#
|
45
|
+
# @return [Fixnum] The size of the collection.
|
46
|
+
def size
|
47
|
+
records.count
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :count, :size
|
51
|
+
alias_method :length, :size
|
52
|
+
|
53
|
+
# Returns the current page cursor.
|
54
|
+
#
|
55
|
+
# @return [String] The current page cursor.
|
56
|
+
def current_page
|
57
|
+
current_cursor
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the next page cursor.
|
61
|
+
#
|
62
|
+
# @return [String] The next page cursor.
|
63
|
+
def next_page
|
64
|
+
next_cursor
|
65
|
+
end
|
66
|
+
|
67
|
+
# Checks if the collection is empty.
|
68
|
+
#
|
69
|
+
# @return [Boolean] `true` if the collection is empty, `false` otherwise.
|
70
|
+
def empty?
|
71
|
+
records.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
# Checks if the collection has a next page.
|
75
|
+
#
|
76
|
+
# @return [Boolean] `true` if the collection has a next page, `false` otherwise.
|
77
|
+
def next?
|
78
|
+
!next_cursor.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
alias_method :next_page?, :next?
|
82
|
+
alias_method :eof?, :next?
|
83
|
+
|
84
|
+
# Serialize the collection as a Hash that can be serialized as JSON.
|
85
|
+
#
|
86
|
+
# @param options [Hash] The options to use to serialize.
|
87
|
+
# @return [Hash] The serialized collection.
|
88
|
+
def as_json(options = {})
|
89
|
+
{
|
90
|
+
records: records.as_json(options),
|
91
|
+
limit: limit,
|
92
|
+
current_cursor: current_cursor,
|
93
|
+
next_cursor: next_cursor
|
94
|
+
}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of the pinterest-ruby gem. Copyright (C) 2017 and above Shogun <shogun@cowtech.it>.
|
3
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Pinterest
|
7
|
+
# Pinterest API endpoints.
|
8
|
+
module Endpoints
|
9
|
+
# Authentication related endpoints.
|
10
|
+
module Authentication
|
11
|
+
# Returns a state string needed for authorization by the Pinterest API.
|
12
|
+
#
|
13
|
+
# @return [String] The state.
|
14
|
+
def authorization_state
|
15
|
+
@state ||= SecureRandom.hex
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the URL to start the authentication flow.
|
19
|
+
#
|
20
|
+
# @param callback_url [String] The callback where to redirect the browser when done.
|
21
|
+
# @param scopes [Array] The list of scopes to ask for. For a list of valid fields, see `Pinterest::Client::SCOPES`.
|
22
|
+
# @return [String] The authorization URL.
|
23
|
+
def authorization_url(callback_url = nil, scopes = nil)
|
24
|
+
ensure_param(client_id, "You must specify the client_id.")
|
25
|
+
ensure_param(callback_url, "You must specify the callback_url.")
|
26
|
+
validate_callback_url(callback_url)
|
27
|
+
|
28
|
+
# Create the query
|
29
|
+
query = cleanup_params({
|
30
|
+
response_type: "code", client_id: client_id.to_s, authorization_state: authorization_state, redirect_uri: callback_url,
|
31
|
+
scope: (ensure_array(scopes, ::Pinterest::Client::SCOPES) & ::Pinterest::Client::SCOPES).join(",") # Restrict to only valid scopes
|
32
|
+
})
|
33
|
+
|
34
|
+
# Create the URL
|
35
|
+
url = Addressable::URI.parse(::Pinterest::Client::API_URL + "/oauth")
|
36
|
+
url.query_values = query
|
37
|
+
url.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fetches the access token.
|
41
|
+
#
|
42
|
+
# @param [String] authorization_token The authorization token.
|
43
|
+
# @return [String] The authentication token.
|
44
|
+
def fetch_access_token(authorization_token)
|
45
|
+
ensure_param(client_id, "You must specify the client_id.")
|
46
|
+
ensure_param(client_secret, "You must specify the client_secret.")
|
47
|
+
ensure_param(authorization_token, "You must specify the authorization_token.")
|
48
|
+
|
49
|
+
# Create parameters
|
50
|
+
query = cleanup_params({
|
51
|
+
client_id: client_id, client_secret: client_secret,
|
52
|
+
grant_type: "authorization_code", code: authorization_token
|
53
|
+
})
|
54
|
+
|
55
|
+
# Perform the request and then get the token
|
56
|
+
response = perform_network_request(method: :post, url: versioned_url("/oauth/token"), query: query)
|
57
|
+
@access_token = response.body["access_token"]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Verifies the access token.
|
61
|
+
#
|
62
|
+
# @return [Hash] The access token informations.
|
63
|
+
def verify_access_token
|
64
|
+
ensure_param(client_id, "You must specify the client_id.")
|
65
|
+
ensure_param(access_token, "You must set the access token first.")
|
66
|
+
|
67
|
+
# Get the data
|
68
|
+
data = perform_network_request(url: versioned_url("/oauth/inspect"), authenticated: true).body["data"]
|
69
|
+
|
70
|
+
# Prepare for output
|
71
|
+
create_authentication(data)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# :nodoc:
|
77
|
+
def validate_callback_url(url)
|
78
|
+
valid =
|
79
|
+
begin
|
80
|
+
Addressable::URI.parse(url).scheme == "https"
|
81
|
+
rescue
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
raise(ArgumentError, "callback_url must be a valid HTTPS URL.") unless valid
|
86
|
+
end
|
87
|
+
|
88
|
+
# :nodoc:
|
89
|
+
def create_authentication(data)
|
90
|
+
{
|
91
|
+
created_at: ::Pinterest::Entity.parse_timestamp(data["issued_at"]),
|
92
|
+
scopes: data["scopes"],
|
93
|
+
user_id: data["user_id"].to_s,
|
94
|
+
application_id: data["app"]["id"].to_s
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
#
|
2
|
+
# This file is part of the pinterest-ruby gem. Copyright (C) 2017 and above Shogun <shogun@cowtech.it>.
|
3
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Pinterest
|
7
|
+
module Endpoints
|
8
|
+
# Boards related endpoints.
|
9
|
+
module Boards
|
10
|
+
# Returns information about a board.
|
11
|
+
#
|
12
|
+
# @param board [String] The board path (username/id) or user id.
|
13
|
+
# @param fields [Array] A list of fields to return.
|
14
|
+
# @return [Pinterest::Board] A board object.
|
15
|
+
def board(board, fields: nil)
|
16
|
+
# Validate the board id
|
17
|
+
board = validate_board(board)
|
18
|
+
|
19
|
+
# Ensure only valid fields are used
|
20
|
+
fields = ensure_board_fields(fields)
|
21
|
+
|
22
|
+
# Perform the request and create the board
|
23
|
+
data = perform_network_request(url: versioned_url("/boards/#{board}/"), query: cleanup_params({fields: fields.join(",")})).body["data"]
|
24
|
+
::Pinterest::Board.create(data)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the list of the boards of the authenticated user. Pagination is not supported by Pinterest API.
|
28
|
+
#
|
29
|
+
# @param fields [Array] A list of fields to return.
|
30
|
+
# @return [Pinterest::Collection] An collection of board objects.
|
31
|
+
def boards(fields: nil)
|
32
|
+
get_boards_collection("/me/boards/", nil, fields)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a new board.
|
36
|
+
#
|
37
|
+
# @param name [String] The board name.
|
38
|
+
# @param description [String] The board description.
|
39
|
+
# @param fields [Array] A list of fields to return.
|
40
|
+
# @return [Pinterest::Board] The created board object.
|
41
|
+
def create_board(name, description = "", fields: nil)
|
42
|
+
# Validate name
|
43
|
+
ensure_param(name, "You have to specify the board name.")
|
44
|
+
|
45
|
+
# Ensure only valid fields are used
|
46
|
+
fields = ensure_board_fields(fields)
|
47
|
+
|
48
|
+
# Create the board
|
49
|
+
data = perform_network_request(
|
50
|
+
method: "POST", url: versioned_url("/boards/"),
|
51
|
+
query: cleanup_params({fields: fields.join(",")}),
|
52
|
+
body: cleanup_params({name: name, description: description})
|
53
|
+
)
|
54
|
+
|
55
|
+
# Wrap in a object
|
56
|
+
::Pinterest::Board.create(data.body["data"])
|
57
|
+
end
|
58
|
+
|
59
|
+
# Edits a board.
|
60
|
+
#
|
61
|
+
# @param board [Fixnum] The board id.
|
62
|
+
# @param name [String] The new board name.
|
63
|
+
# @param description [String] The new board description.
|
64
|
+
# @param fields [Array] A list of fields to return.
|
65
|
+
# @return [Pinterest::Board] The updated board object.
|
66
|
+
def edit_board(board, name: nil, description: nil, fields: nil)
|
67
|
+
# Validate the board id
|
68
|
+
raise(ArgumentError, "You have to specify a board or its id.") unless board
|
69
|
+
board = board.id if board.is_a?(::Pinterest::Board)
|
70
|
+
|
71
|
+
# Ensure only valid fields are used
|
72
|
+
fields = ensure_board_fields(fields)
|
73
|
+
|
74
|
+
# Create the board
|
75
|
+
data = perform_network_request(
|
76
|
+
method: "PATCH", url: versioned_url("/boards/#{board}/"),
|
77
|
+
query: cleanup_params(fields: fields.join(",")),
|
78
|
+
body: cleanup_params({name: name, description: description})
|
79
|
+
)
|
80
|
+
|
81
|
+
# Wrap in a object
|
82
|
+
::Pinterest::Board.create(data.body["data"])
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deletes a board.
|
86
|
+
#
|
87
|
+
# @param board [Fixnum] The board id.
|
88
|
+
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
89
|
+
def delete_board(board)
|
90
|
+
# Validate the board id
|
91
|
+
board = validate_board(board)
|
92
|
+
|
93
|
+
# Perform the request
|
94
|
+
perform_network_request(method: "DELETE", url: versioned_url("/boards/#{board}/"))
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
# Search between of boards of the authenticated user.
|
99
|
+
#
|
100
|
+
# @param query [String] The query to perform.
|
101
|
+
# @param fields [Array] A list of fields to return.
|
102
|
+
# @param cursor [String] A cursor to paginate results, obtained by a previous call.
|
103
|
+
# @param limit [Fixnum] The maximum number of objects to return.
|
104
|
+
# @return [Pinterest::Collection] An collection of board objects.
|
105
|
+
def search_my_boards(query, fields: nil, cursor: nil, limit: nil)
|
106
|
+
ensure_param(query, "You have to specify a query.")
|
107
|
+
get_boards_collection("/me/search/boards/", {query: query}, fields, cursor, limit)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the list of boards of suggested boards for the authenticated user.
|
111
|
+
#
|
112
|
+
# @param fields [Array] A list of fields to return.
|
113
|
+
# @param cursor [String] A cursor to paginate results, obtained by a previous call.
|
114
|
+
# @param limit [Fixnum] The maximum number of objects to return.
|
115
|
+
# @return [Pinterest::Collection] An collection of board objects.
|
116
|
+
def suggested_boards(fields: nil, cursor: nil, limit: nil)
|
117
|
+
get_boards_collection("/me/boards/suggested/", nil, fields, cursor, limit)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns the list of boards followed by the authenticated user.
|
121
|
+
#
|
122
|
+
# @param fields [Array] A list of fields to return.
|
123
|
+
# @param cursor [String] A cursor to paginate results, obtained by a previous call.
|
124
|
+
# @param limit [Fixnum] The maximum number of objects to return.
|
125
|
+
# @return [Pinterest::Collection] An collection of board objects.
|
126
|
+
def following_boards(fields: nil, cursor: nil, limit: nil)
|
127
|
+
get_boards_collection("/me/following/boards/", nil, fields, cursor, limit)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Follows a board.
|
131
|
+
#
|
132
|
+
# @param board [String] The board id.
|
133
|
+
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
134
|
+
def follow_board(board)
|
135
|
+
# Validate the board id
|
136
|
+
board = validate_board(board)
|
137
|
+
|
138
|
+
# Perform the request
|
139
|
+
perform_network_request(method: "POST", query: {board: board}, url: versioned_url("/me/following/boards/"))
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
# Stop following a board.
|
144
|
+
#
|
145
|
+
# @param board [String] The board id.
|
146
|
+
# @return [Boolean] `true` if operation succeeded, `false` otherwise.
|
147
|
+
def unfollow_board(board)
|
148
|
+
# Validate the board id
|
149
|
+
board = validate_board(board)
|
150
|
+
|
151
|
+
# Perform the request
|
152
|
+
perform_network_request(method: "DELETE", url: versioned_url("/me/following/boards/#{board}/"))
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
# :nodoc:
|
159
|
+
def get_boards_collection(path, params, fields, cursor = nil, limit = nil)
|
160
|
+
# Ensure only valid fields are used and merge params
|
161
|
+
fields = ensure_board_fields(fields)
|
162
|
+
params ||= {}
|
163
|
+
params[:fields] = fields.join(",")
|
164
|
+
|
165
|
+
# Perform the request
|
166
|
+
data = perform_network_request(
|
167
|
+
url: versioned_url(path),
|
168
|
+
query: cleanup_params(params),
|
169
|
+
pagination: (cursor || limit), cursor: cursor, limit: limit
|
170
|
+
)
|
171
|
+
|
172
|
+
# Create the collection
|
173
|
+
::Pinterest::Collection.new(data.body, cursor, limit) { |board| ::Pinterest::Board.create(board) }
|
174
|
+
end
|
175
|
+
|
176
|
+
# :nodoc:
|
177
|
+
def validate_board(board)
|
178
|
+
raise(ArgumentError, "You have to specify a board or its id.") unless board
|
179
|
+
board = board.id if board.is_a?(::Pinterest::Board)
|
180
|
+
board
|
181
|
+
end
|
182
|
+
|
183
|
+
# :nodoc:
|
184
|
+
def ensure_board_fields(fields = nil)
|
185
|
+
# Get fields and make sure only allowed fields are kept
|
186
|
+
fields = ensure_array(fields, ::Pinterest::Board::FIELDS).map(&:to_s) & ::Pinterest::Board::FIELDS
|
187
|
+
|
188
|
+
# Replace embedded fields
|
189
|
+
fields.map { |f| f == "creator" ? "creator(#{ensure_user_fields.join(",")})" : f }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|