pinterest-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +63 -0
  4. data/.travis-gemfile +17 -0
  5. data/.travis.yml +12 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +3 -0
  8. data/Gemfile +24 -0
  9. data/README.md +34 -0
  10. data/Rakefile +44 -0
  11. data/docs/FaradayMiddleware/SafeOj.html +218 -0
  12. data/docs/FaradayMiddleware.html +125 -0
  13. data/docs/Pinterest/Board.html +410 -0
  14. data/docs/Pinterest/Client.html +1894 -0
  15. data/docs/Pinterest/Collection.html +1877 -0
  16. data/docs/Pinterest/Endpoints/Authentication.html +578 -0
  17. data/docs/Pinterest/Endpoints/Boards.html +1443 -0
  18. data/docs/Pinterest/Endpoints/Pins.html +1296 -0
  19. data/docs/Pinterest/Endpoints/Users.html +1220 -0
  20. data/docs/Pinterest/Endpoints.html +127 -0
  21. data/docs/Pinterest/Entity.html +473 -0
  22. data/docs/Pinterest/Errors/AuthorizationError.html +158 -0
  23. data/docs/Pinterest/Errors/BadRequestError.html +158 -0
  24. data/docs/Pinterest/Errors/BaseError.html +487 -0
  25. data/docs/Pinterest/Errors/MethodNotAllowedError.html +158 -0
  26. data/docs/Pinterest/Errors/NotFoundError.html +158 -0
  27. data/docs/Pinterest/Errors/NotImplementedError.html +158 -0
  28. data/docs/Pinterest/Errors/PermissionsError.html +158 -0
  29. data/docs/Pinterest/Errors/RateLimitError.html +158 -0
  30. data/docs/Pinterest/Errors/ServerError.html +158 -0
  31. data/docs/Pinterest/Errors/TimeoutError.html +158 -0
  32. data/docs/Pinterest/Errors.html +377 -0
  33. data/docs/Pinterest/Image.html +617 -0
  34. data/docs/Pinterest/Interest.html +402 -0
  35. data/docs/Pinterest/Pin.html +511 -0
  36. data/docs/Pinterest/User.html +408 -0
  37. data/docs/Pinterest/Version.html +187 -0
  38. data/docs/Pinterest.html +130 -0
  39. data/docs/_index.html +401 -0
  40. data/docs/class_list.html +51 -0
  41. data/docs/css/common.css +1 -0
  42. data/docs/css/full_list.css +58 -0
  43. data/docs/css/style.css +492 -0
  44. data/docs/file.README.html +106 -0
  45. data/docs/file_list.html +56 -0
  46. data/docs/frames.html +17 -0
  47. data/docs/index.html +106 -0
  48. data/docs/js/app.js +243 -0
  49. data/docs/js/full_list.js +216 -0
  50. data/docs/js/jquery.js +4 -0
  51. data/docs/method_list.html +643 -0
  52. data/docs/top-level-namespace.html +110 -0
  53. data/lib/pinterest/client.rb +146 -0
  54. data/lib/pinterest/collection.rb +97 -0
  55. data/lib/pinterest/endpoints/authentication.rb +99 -0
  56. data/lib/pinterest/endpoints/boards.rb +193 -0
  57. data/lib/pinterest/endpoints/pins.rb +187 -0
  58. data/lib/pinterest/endpoints/users.rb +158 -0
  59. data/lib/pinterest/errors.rb +94 -0
  60. data/lib/pinterest/models/board.rb +34 -0
  61. data/lib/pinterest/models/entity.rb +42 -0
  62. data/lib/pinterest/models/image.rb +49 -0
  63. data/lib/pinterest/models/interest.rb +30 -0
  64. data/lib/pinterest/models/pin.rb +43 -0
  65. data/lib/pinterest/models/user.rb +33 -0
  66. data/lib/pinterest/safe_oj.rb +25 -0
  67. data/lib/pinterest/version.rb +23 -0
  68. data/lib/pinterest.rb +31 -0
  69. data/pinterest.gemspec +32 -0
  70. data/spec/cassettes/Pinterest_Client/_perform_network_request_private_/should_correctly_handle_malformed_requests.yml +51 -0
  71. 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
  72. data/spec/cassettes/Pinterest_Endpoints_Authentication/_verify_access_token/should_return_an_exception_when_using_an_invalid_token.yml +52 -0
  73. data/spec/cassettes/Pinterest_Endpoints_Authentication/_verify_access_token/should_verify_the_token.yml +59 -0
  74. data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_complain_for_invalid_boards.yml +48 -0
  75. data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_get_the_current_informations.yml +63 -0
  76. data/spec/cassettes/Pinterest_Endpoints_Boards/_board/should_restrict_to_requested_fields.yml +57 -0
  77. data/spec/cassettes/Pinterest_Endpoints_Boards/_boards/should_only_get_requested_fields.yml +57 -0
  78. data/spec/cassettes/Pinterest_Endpoints_Boards/_boards/should_return_a_list_of_boards.yml +74 -0
  79. data/spec/cassettes/Pinterest_Endpoints_Boards/_create_board/should_create_the_board_and_return_it_with_only_the_requested_fields.yml +56 -0
  80. data/spec/cassettes/Pinterest_Endpoints_Boards/_delete_board/should_perform_the_call_and_return_an_error.yml +48 -0
  81. data/spec/cassettes/Pinterest_Endpoints_Boards/_delete_board/should_perform_the_call_and_return_true.yml +109 -0
  82. data/spec/cassettes/Pinterest_Endpoints_Boards/_edit_board/should_edit_the_board_and_return_it_with_only_the_requested_fields.yml +56 -0
  83. data/spec/cassettes/Pinterest_Endpoints_Boards/_follow_board/should_complain_for_invalid_boards.yml +56 -0
  84. data/spec/cassettes/Pinterest_Endpoints_Boards/_follow_board/should_perform_the_call_and_return_true.yml +109 -0
  85. data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_only_get_requested_fields.yml +59 -0
  86. data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_paginate_correctly.yml +72 -0
  87. data/spec/cassettes/Pinterest_Endpoints_Boards/_following_boards/should_return_the_followed_boards.yml +72 -0
  88. data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_only_get_requested_fields.yml +59 -0
  89. data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_paginate_correctly.yml +66 -0
  90. data/spec/cassettes/Pinterest_Endpoints_Boards/_search_my_boards/should_search_boards.yml +75 -0
  91. data/spec/cassettes/Pinterest_Endpoints_Boards/_suggested_boards/should_return_the_suggested_boards_returning_only_the_requested_fields.yml +56 -0
  92. data/spec/cassettes/Pinterest_Endpoints_Boards/_unfollow_board/should_complain_for_invalid_boards.yml +56 -0
  93. data/spec/cassettes/Pinterest_Endpoints_Boards/_unfollow_board/should_perform_the_call_and_return_true.yml +109 -0
  94. data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_only_get_requested_fields.yml +59 -0
  95. data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_paginate_correctly.yml +85 -0
  96. data/spec/cassettes/Pinterest_Endpoints_Pins/_board_pins/should_return_the_pins_of_the_board.yml +85 -0
  97. data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_create_a_pin_by_using_a_image_URL.yml +71 -0
  98. data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_create_a_pin_by_using_a_image_file.yml +1997 -0
  99. data/spec/cassettes/Pinterest_Endpoints_Pins/_create_pin/should_return_a_pin_containing_only_requested_fields.yml +56 -0
  100. data/spec/cassettes/Pinterest_Endpoints_Pins/_delete_pin/should_perform_the_call_and_return_an_error.yml +56 -0
  101. data/spec/cassettes/Pinterest_Endpoints_Pins/_delete_pin/should_perform_the_call_and_return_true.yml +109 -0
  102. data/spec/cassettes/Pinterest_Endpoints_Pins/_edit_pin/should_edit_the_pin_and_return_it_with_only_the_requested_fields.yml +56 -0
  103. data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_only_get_requested_fields.yml +58 -0
  104. data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_paginate_correctly.yml +87 -0
  105. data/spec/cassettes/Pinterest_Endpoints_Pins/_likes/should_return_the_list_of_liked_pins.yml +85 -0
  106. data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_complain_for_non_existent_pins.yml +56 -0
  107. data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_get_the_current_informations.yml +71 -0
  108. data/spec/cassettes/Pinterest_Endpoints_Pins/_pin/should_restrict_to_requested_fields.yml +56 -0
  109. data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_only_get_requested_fields.yml +59 -0
  110. data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_paginate_correctly.yml +808 -0
  111. data/spec/cassettes/Pinterest_Endpoints_Pins/_pins/should_return_my_pins.yml +88 -0
  112. data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_only_get_requested_fields.yml +61 -0
  113. data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_paginate_correctly.yml +89 -0
  114. data/spec/cassettes/Pinterest_Endpoints_Pins/_search_my_pins/should_search_my_pins.yml +89 -0
  115. data/spec/cassettes/Pinterest_Endpoints_Users/_follow_interest/should_perform_the_call_and_return_an_error.yml +48 -0
  116. data/spec/cassettes/Pinterest_Endpoints_Users/_follow_user/should_complain_for_invalid_users.yml +56 -0
  117. data/spec/cassettes/Pinterest_Endpoints_Users/_follow_user/should_perform_the_call_and_return_true.yml +109 -0
  118. data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_only_get_requested_fields.yml +62 -0
  119. data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_paginate_correctly.yml +62 -0
  120. data/spec/cassettes/Pinterest_Endpoints_Users/_followers/should_return_a_list_of_followers.yml +62 -0
  121. data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_only_get_requested_fields.yml +62 -0
  122. data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_paginate_correctly.yml +131 -0
  123. data/spec/cassettes/Pinterest_Endpoints_Users/_following_users/should_return_a_list_of_followed_users.yml +66 -0
  124. data/spec/cassettes/Pinterest_Endpoints_Users/_interests/should_paginate_correctly.yml +112 -0
  125. data/spec/cassettes/Pinterest_Endpoints_Users/_interests/should_return_a_list_of_followed_interest.yml +58 -0
  126. data/spec/cassettes/Pinterest_Endpoints_Users/_me/should_get_the_current_informations.yml +62 -0
  127. data/spec/cassettes/Pinterest_Endpoints_Users/_me/should_restrict_to_requested_fields.yml +56 -0
  128. data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_interest/should_perform_the_call_and_return_an_error.yml +48 -0
  129. data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_user/should_complain_for_invalid_users.yml +56 -0
  130. data/spec/cassettes/Pinterest_Endpoints_Users/_unfollow_user/should_perform_the_call_and_return_true.yml +109 -0
  131. data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_complain_for_non_existent_users.yml +56 -0
  132. data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_get_the_current_informations.yml +60 -0
  133. data/spec/cassettes/Pinterest_Endpoints_Users/_user/should_restrict_to_requested_fields.yml +56 -0
  134. data/spec/pinterest/client_spec.rb +70 -0
  135. data/spec/pinterest/collection_spec.rb +82 -0
  136. data/spec/pinterest/endpoints/authentication_spec.rb +81 -0
  137. data/spec/pinterest/endpoints/boards_spec.rb +209 -0
  138. data/spec/pinterest/endpoints/pins_spec.rb +239 -0
  139. data/spec/pinterest/endpoints/users_spec.rb +194 -0
  140. data/spec/pinterest/errors_spec.rb +59 -0
  141. data/spec/pinterest/fixtures/first.jpg +0 -0
  142. data/spec/pinterest/models/board_spec.rb +48 -0
  143. data/spec/pinterest/models/entity_spec.rb +35 -0
  144. data/spec/pinterest/models/image_spec.rb +50 -0
  145. data/spec/pinterest/models/interest_spec.rb +20 -0
  146. data/spec/pinterest/models/pin_spec.rb +55 -0
  147. data/spec/pinterest/models/user_spec.rb +45 -0
  148. data/spec/spec_helper.rb +49 -0
  149. data/tester.rb +19 -0
  150. 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
+ &mdash; 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> &raquo;
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