pinterest-ruby 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|