twitter 5.17.0 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +37 -10
  3. data/LICENSE.md +1 -1
  4. data/README.md +78 -407
  5. data/lib/twitter/base.rb +5 -19
  6. data/lib/twitter/basic_user.rb +0 -3
  7. data/lib/twitter/client.rb +9 -23
  8. data/lib/twitter/configuration.rb +4 -4
  9. data/lib/twitter/creatable.rb +5 -1
  10. data/lib/twitter/cursor.rb +13 -4
  11. data/lib/twitter/direct_message.rb +2 -0
  12. data/lib/twitter/direct_message_event.rb +44 -0
  13. data/lib/twitter/direct_messages/welcome_message.rb +17 -0
  14. data/lib/twitter/direct_messages/welcome_message_rule.rb +12 -0
  15. data/lib/twitter/direct_messages/welcome_message_rule_wrapper.rb +36 -0
  16. data/lib/twitter/direct_messages/welcome_message_wrapper.rb +42 -0
  17. data/lib/twitter/entity/uri.rb +0 -4
  18. data/lib/twitter/enumerable.rb +14 -3
  19. data/lib/twitter/error.rb +122 -95
  20. data/lib/twitter/geo_results.rb +0 -1
  21. data/lib/twitter/headers.rb +11 -15
  22. data/lib/twitter/media/photo.rb +5 -2
  23. data/lib/twitter/media/video.rb +5 -2
  24. data/lib/twitter/media/video_info.rb +1 -1
  25. data/lib/twitter/null_object.rb +20 -7
  26. data/lib/twitter/premium_search_results.rb +67 -0
  27. data/lib/twitter/profile.rb +5 -4
  28. data/lib/twitter/profile_banner.rb +1 -2
  29. data/lib/twitter/rate_limit.rb +3 -3
  30. data/lib/twitter/rest/account_activity.rb +99 -0
  31. data/lib/twitter/rest/api.rb +6 -2
  32. data/lib/twitter/rest/client.rb +0 -78
  33. data/lib/twitter/rest/direct_messages/welcome_messages.rb +90 -0
  34. data/lib/twitter/rest/direct_messages.rb +133 -44
  35. data/lib/twitter/rest/favorites.rb +29 -8
  36. data/lib/twitter/rest/friends_and_followers.rb +1 -3
  37. data/lib/twitter/rest/lists.rb +20 -30
  38. data/lib/twitter/rest/oauth.rb +15 -15
  39. data/lib/twitter/rest/premium_search.rb +34 -0
  40. data/lib/twitter/rest/request.rb +133 -18
  41. data/lib/twitter/rest/saved_searches.rb +1 -3
  42. data/lib/twitter/rest/search.rb +6 -3
  43. data/lib/twitter/rest/timelines.rb +1 -0
  44. data/lib/twitter/rest/trends.rb +1 -0
  45. data/lib/twitter/rest/tweets.rb +54 -18
  46. data/lib/twitter/rest/undocumented.rb +3 -4
  47. data/lib/twitter/rest/upload_utils.rb +68 -0
  48. data/lib/twitter/rest/users.rb +23 -37
  49. data/lib/twitter/rest/utils.rb +38 -28
  50. data/lib/twitter/search_results.rb +4 -4
  51. data/lib/twitter/streaming/client.rb +23 -25
  52. data/lib/twitter/streaming/connection.rb +37 -11
  53. data/lib/twitter/streaming/deleted_tweet.rb +0 -1
  54. data/lib/twitter/streaming/event.rb +6 -6
  55. data/lib/twitter/streaming/message_parser.rb +1 -1
  56. data/lib/twitter/streaming/response.rb +7 -3
  57. data/lib/twitter/trend_results.rb +1 -2
  58. data/lib/twitter/tweet.rb +11 -6
  59. data/lib/twitter/user.rb +2 -4
  60. data/lib/twitter/utils.rb +5 -18
  61. data/lib/twitter/version.rb +6 -6
  62. data/lib/twitter.rb +5 -0
  63. data/twitter.gemspec +10 -11
  64. metadata +31 -42
  65. data/lib/twitter/rest/media.rb +0 -30
  66. data/lib/twitter/rest/request/multipart_with_file.rb +0 -47
  67. data/lib/twitter/rest/response/parse_error_json.rb +0 -13
  68. data/lib/twitter/rest/response/parse_json.rb +0 -31
  69. data/lib/twitter/rest/response/raise_error.rb +0 -32
  70. data/lib/twitter/token.rb +0 -20
data/lib/twitter/error.rb CHANGED
@@ -8,7 +8,110 @@ module Twitter
8
8
  # @return [Twitter::RateLimit]
9
9
  attr_reader :rate_limit
10
10
 
11
- # If error code is missing see https://dev.twitter.com/overview/api/response-codes
11
+ # Raised when Twitter returns a 4xx HTTP status code
12
+ ClientError = Class.new(self)
13
+
14
+ # Raised when Twitter returns the HTTP status code 400
15
+ BadRequest = Class.new(ClientError)
16
+
17
+ # Raised when Twitter returns the HTTP status code 401
18
+ Unauthorized = Class.new(ClientError)
19
+
20
+ # Raised when Twitter returns the HTTP status code 403
21
+ Forbidden = Class.new(ClientError)
22
+
23
+ # Raised when Twitter returns the HTTP status code 413
24
+ RequestEntityTooLarge = Class.new(ClientError)
25
+
26
+ # Raised when a Tweet has already been favorited
27
+ AlreadyFavorited = Class.new(Forbidden)
28
+
29
+ # Raised when a Tweet has already been retweeted
30
+ AlreadyRetweeted = Class.new(Forbidden)
31
+
32
+ # Raised when a Tweet has already been posted
33
+ DuplicateStatus = Class.new(Forbidden)
34
+
35
+ # Raised when Twitter returns the HTTP status code 404
36
+ NotFound = Class.new(ClientError)
37
+
38
+ # Raised when Twitter returns the HTTP status code 406
39
+ NotAcceptable = Class.new(ClientError)
40
+
41
+ # Raised when Twitter returns the HTTP status code 422
42
+ UnprocessableEntity = Class.new(ClientError)
43
+
44
+ # Raised when Twitter returns the HTTP status code 429
45
+ TooManyRequests = Class.new(ClientError)
46
+
47
+ # Raised when Twitter returns a 5xx HTTP status code
48
+ ServerError = Class.new(self)
49
+
50
+ # Raised when Twitter returns the HTTP status code 500
51
+ InternalServerError = Class.new(ServerError)
52
+
53
+ # Raised when Twitter returns the HTTP status code 502
54
+ BadGateway = Class.new(ServerError)
55
+
56
+ # Raised when Twitter returns the HTTP status code 503
57
+ ServiceUnavailable = Class.new(ServerError)
58
+
59
+ # Raised when Twitter returns the HTTP status code 504
60
+ GatewayTimeout = Class.new(ServerError)
61
+
62
+ # Raised when Twitter returns a media related error
63
+ MediaError = Class.new(self)
64
+
65
+ # Raised when Twitter returns an InvalidMedia error
66
+ InvalidMedia = Class.new(MediaError)
67
+
68
+ # Raised when Twitter returns a media InternalError error
69
+ MediaInternalError = Class.new(MediaError)
70
+
71
+ # Raised when Twitter returns an UnsupportedMedia error
72
+ UnsupportedMedia = Class.new(MediaError)
73
+
74
+ # Raised when an operation subject to timeout takes too long
75
+ TimeoutError = Class.new(self)
76
+
77
+ ERRORS = {
78
+ 400 => Twitter::Error::BadRequest,
79
+ 401 => Twitter::Error::Unauthorized,
80
+ 403 => Twitter::Error::Forbidden,
81
+ 404 => Twitter::Error::NotFound,
82
+ 406 => Twitter::Error::NotAcceptable,
83
+ 413 => Twitter::Error::RequestEntityTooLarge,
84
+ 422 => Twitter::Error::UnprocessableEntity,
85
+ 429 => Twitter::Error::TooManyRequests,
86
+ 500 => Twitter::Error::InternalServerError,
87
+ 502 => Twitter::Error::BadGateway,
88
+ 503 => Twitter::Error::ServiceUnavailable,
89
+ 504 => Twitter::Error::GatewayTimeout,
90
+ }.freeze
91
+
92
+ FORBIDDEN_MESSAGES = proc do |message|
93
+ case message
94
+ when /(?=.*status).*duplicate/i
95
+ # - "Status is a duplicate."
96
+ Twitter::Error::DuplicateStatus
97
+ when /already favorited/i
98
+ # - "You have already favorited this status."
99
+ Twitter::Error::AlreadyFavorited
100
+ when /already retweeted|Share validations failed/i
101
+ # - "You have already retweeted this Tweet." (Nov 2017-)
102
+ # - "You have already retweeted this tweet." (?-Nov 2017)
103
+ # - "sharing is not permissible for this status (Share validations failed)" (-? 2017)
104
+ Twitter::Error::AlreadyRetweeted
105
+ end
106
+ end
107
+
108
+ MEDIA_ERRORS = {
109
+ 'InternalError' => Twitter::Error::MediaInternalError,
110
+ 'InvalidMedia' => Twitter::Error::InvalidMedia,
111
+ 'UnsupportedMedia' => Twitter::Error::UnsupportedMedia,
112
+ }.freeze
113
+
114
+ # If error code is missing see https://developer.twitter.com/en/docs/basics/response-codes
12
115
  module Code
13
116
  AUTHENTICATION_PROBLEM = 32
14
117
  RESOURCE_NOT_FOUND = 34
@@ -35,49 +138,36 @@ module Twitter
35
138
  CANNOT_MUTE = 271
36
139
  CANNOT_UNMUTE = 272
37
140
  end
38
- Codes = Code
39
141
 
40
142
  class << self
143
+ include Twitter::Utils
144
+
41
145
  # Create a new error from an HTTP response
42
146
  #
43
- # @param response [Faraday::Response]
147
+ # @param body [String]
148
+ # @param headers [Hash]
44
149
  # @return [Twitter::Error]
45
- def from_response(response)
46
- message, code = parse_error(response.body)
47
- new(message, response.response_headers, code)
48
- end
49
-
50
- # @return [Hash]
51
- def errors
52
- @errors ||= {
53
- 400 => Twitter::Error::BadRequest,
54
- 401 => Twitter::Error::Unauthorized,
55
- 403 => Twitter::Error::Forbidden,
56
- 404 => Twitter::Error::NotFound,
57
- 406 => Twitter::Error::NotAcceptable,
58
- 408 => Twitter::Error::RequestTimeout,
59
- 420 => Twitter::Error::EnhanceYourCalm,
60
- 422 => Twitter::Error::UnprocessableEntity,
61
- 429 => Twitter::Error::TooManyRequests,
62
- 500 => Twitter::Error::InternalServerError,
63
- 502 => Twitter::Error::BadGateway,
64
- 503 => Twitter::Error::ServiceUnavailable,
65
- 504 => Twitter::Error::GatewayTimeout,
66
- }
150
+ def from_response(body, headers)
151
+ message, code = parse_error(body)
152
+ new(message, headers, code)
67
153
  end
68
154
 
69
- def forbidden_messages
70
- @forbidden_messages ||= {
71
- 'Status is a duplicate.' => Twitter::Error::DuplicateStatus,
72
- 'You have already favorited this status.' => Twitter::Error::AlreadyFavorited,
73
- 'sharing is not permissible for this status (Share validations failed)' => Twitter::Error::AlreadyRetweeted,
74
- }
155
+ # Create a new error from a media error hash
156
+ #
157
+ # @param error [Hash]
158
+ # @param headers [Hash]
159
+ # @return [Twitter::MediaError]
160
+ def from_processing_response(error, headers)
161
+ klass = MEDIA_ERRORS[error[:name]] || self
162
+ message = error[:message]
163
+ code = error[:code]
164
+ klass.new(message, headers, code)
75
165
  end
76
166
 
77
167
  private
78
168
 
79
169
  def parse_error(body)
80
- if body.nil?
170
+ if body.nil? || body.empty?
81
171
  ['', nil]
82
172
  elsif body[:error]
83
173
  [body[:error], nil]
@@ -107,68 +197,5 @@ module Twitter
107
197
  @rate_limit = Twitter::RateLimit.new(rate_limit)
108
198
  @code = code
109
199
  end
110
-
111
- ConfigurationError = Class.new(::ArgumentError)
112
-
113
- # Raised when a Tweet includes media that doesn't have a to_io method
114
- class UnacceptableIO < StandardError
115
- def initialize
116
- super('The IO object for media must respond to to_io')
117
- end
118
- end
119
-
120
- # Raised when Twitter returns a 4xx HTTP status code
121
- ClientError = Class.new(self)
122
-
123
- # Raised when Twitter returns the HTTP status code 400
124
- BadRequest = Class.new(ClientError)
125
-
126
- # Raised when Twitter returns the HTTP status code 401
127
- Unauthorized = Class.new(ClientError)
128
-
129
- # Raised when Twitter returns the HTTP status code 403
130
- Forbidden = Class.new(ClientError)
131
-
132
- # Raised when a Tweet has already been favorited
133
- AlreadyFavorited = Class.new(Forbidden)
134
-
135
- # Raised when a Tweet has already been retweeted
136
- AlreadyRetweeted = Class.new(Forbidden)
137
-
138
- # Raised when a Tweet has already been posted
139
- DuplicateStatus = Class.new(Forbidden)
140
- AlreadyPosted = DuplicateStatus
141
-
142
- # Raised when Twitter returns the HTTP status code 404
143
- NotFound = Class.new(ClientError)
144
-
145
- # Raised when Twitter returns the HTTP status code 406
146
- NotAcceptable = Class.new(ClientError)
147
-
148
- # Raised when Twitter returns the HTTP status code 408
149
- RequestTimeout = Class.new(ClientError)
150
-
151
- # Raised when Twitter returns the HTTP status code 422
152
- UnprocessableEntity = Class.new(ClientError)
153
-
154
- # Raised when Twitter returns the HTTP status code 429
155
- TooManyRequests = Class.new(ClientError)
156
- EnhanceYourCalm = TooManyRequests
157
- RateLimited = TooManyRequests
158
-
159
- # Raised when Twitter returns a 5xx HTTP status code
160
- ServerError = Class.new(self)
161
-
162
- # Raised when Twitter returns the HTTP status code 500
163
- InternalServerError = Class.new(ServerError)
164
-
165
- # Raised when Twitter returns the HTTP status code 502
166
- BadGateway = Class.new(ServerError)
167
-
168
- # Raised when Twitter returns the HTTP status code 503
169
- ServiceUnavailable = Class.new(ServerError)
170
-
171
- # Raised when Twitter returns the HTTP status code 504
172
- GatewayTimeout = Class.new(ServerError)
173
200
  end
174
201
  end
@@ -9,7 +9,6 @@ module Twitter
9
9
  attr_reader :attrs
10
10
  alias to_h attrs
11
11
  alias to_hash to_h
12
- deprecate_alias :to_hsh, :to_hash
13
12
 
14
13
  # Initializes a new GeoResults object
15
14
  #
@@ -8,21 +8,24 @@ module Twitter
8
8
  @client = client
9
9
  @request_method = request_method.to_sym
10
10
  @uri = Addressable::URI.parse(url)
11
+ @bearer_token_request = options.delete(:bearer_token_request)
11
12
  @options = options
12
- @signature_options = @request_method == :post && @options.values.any? { |value| value.respond_to?(:to_io) } ? {} : @options
13
+ end
14
+
15
+ def bearer_token_request?
16
+ !!@bearer_token_request
13
17
  end
14
18
 
15
19
  def oauth_auth_header
16
- SimpleOAuth::Header.new(@request_method, @uri, @signature_options, @client.credentials)
20
+ SimpleOAuth::Header.new(@request_method, @uri, @options, @client.credentials.merge(ignore_extra_keys: true))
17
21
  end
18
22
 
19
23
  def request_headers
20
- bearer_token_request = @options.delete(:bearer_token_request)
21
24
  headers = {}
22
- if bearer_token_request
25
+ headers[:user_agent] = @client.user_agent
26
+ if bearer_token_request?
23
27
  headers[:accept] = '*/*'
24
28
  headers[:authorization] = bearer_token_credentials_auth_header
25
- headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
26
29
  else
27
30
  headers[:authorization] = auth_header
28
31
  end
@@ -40,23 +43,16 @@ module Twitter
40
43
  end
41
44
  end
42
45
 
46
+ # @return [String]
43
47
  def bearer_auth_header
44
- bearer_token = @client.bearer_token
45
- token = bearer_token.is_a?(Twitter::Token) && bearer_token.bearer? ? bearer_token.access_token : bearer_token
46
- "Bearer #{token}"
48
+ "Bearer #{@client.bearer_token}"
47
49
  end
48
50
 
49
51
  # Generates authentication header for a bearer token request
50
52
  #
51
53
  # @return [String]
52
54
  def bearer_token_credentials_auth_header
53
- basic_auth_token = strict_encode64("#{@client.consumer_key}:#{@client.consumer_secret}")
54
- "Basic #{basic_auth_token}"
55
- end
56
-
57
- # Base64.strict_encode64 is not available on Ruby 1.8.7
58
- def strict_encode64(str)
59
- Base64.encode64(str).delete("\n")
55
+ "Basic #{Base64.strict_encode64("#{@client.consumer_key}:#{@client.consumer_secret}")}"
60
56
  end
61
57
  end
62
58
  end
@@ -8,6 +8,10 @@ module Twitter
8
8
 
9
9
  # @return [Array<Integer>]
10
10
  attr_reader :indices
11
+
12
+ # @return [String]
13
+ attr_reader :type
14
+
11
15
  display_uri_attr_reader
12
16
  uri_attr_reader :expanded_uri, :media_uri, :media_uri_https, :uri
13
17
 
@@ -15,9 +19,8 @@ module Twitter
15
19
  #
16
20
  # @return [Array<Twitter::Size>]
17
21
  def sizes
18
- @attrs.fetch(:sizes, []).inject({}) do |object, (key, value)|
22
+ @attrs.fetch(:sizes, []).each_with_object({}) do |(key, value), object|
19
23
  object[key] = Size.new(value)
20
- object
21
24
  end
22
25
  end
23
26
  memoize :sizes
@@ -9,6 +9,10 @@ module Twitter
9
9
 
10
10
  # @return [Array<Integer>]
11
11
  attr_reader :indices
12
+
13
+ # @return [String]
14
+ attr_reader :type
15
+
12
16
  display_uri_attr_reader
13
17
  uri_attr_reader :expanded_uri, :media_uri, :media_uri_https, :uri
14
18
 
@@ -16,9 +20,8 @@ module Twitter
16
20
  #
17
21
  # @return [Array<Twitter::Size>]
18
22
  def sizes
19
- @attrs.fetch(:sizes, []).inject({}) do |object, (key, value)|
23
+ @attrs.fetch(:sizes, []).each_with_object({}) do |(key, value), object|
20
24
  object[key] = Size.new(value)
21
- object
22
25
  end
23
26
  end
24
27
  memoize :sizes
@@ -16,7 +16,7 @@ module Twitter
16
16
  #
17
17
  # @return [Array<Twitter::Variant>]
18
18
  def variants
19
- @attrs.fetch(:variants, []).map do |variant|
19
+ @attrs.fetch(:variants, []).collect do |variant|
20
20
  Variant.new(variant)
21
21
  end
22
22
  end
@@ -1,7 +1,7 @@
1
1
  require 'naught'
2
2
 
3
3
  module Twitter
4
- NullObject = Naught.build do |config|
4
+ NullObject = Naught.build do |config| # rubocop:disable Metrics/BlockLength
5
5
  include Comparable
6
6
 
7
7
  config.black_hole
@@ -9,22 +9,23 @@ module Twitter
9
9
  config.define_implicit_conversions
10
10
  config.predicates_return false
11
11
 
12
- # TODO: Add when support for Ruby 1.8.7 is dropped
13
- # def !
14
- # true
15
- # end
12
+ def !
13
+ true
14
+ end
16
15
 
17
16
  def respond_to?(*)
18
17
  true
19
18
  end
20
19
 
21
20
  def instance_of?(klass)
22
- raise(TypeError.new('class or module required')) unless klass.is_a?(Class)
21
+ raise(TypeError, 'class or module required') unless klass.is_a?(Class)
22
+
23
23
  self.class == klass
24
24
  end
25
25
 
26
26
  def kind_of?(mod)
27
- raise(TypeError.new('class or module required')) unless mod.is_a?(Module)
27
+ raise(TypeError, 'class or module required') unless mod.is_a?(Module)
28
+
28
29
  self.class.ancestors.include?(mod)
29
30
  end
30
31
 
@@ -49,5 +50,17 @@ module Twitter
49
50
  def to_json(*args)
50
51
  nil.to_json(*args)
51
52
  end
53
+
54
+ def presence
55
+ nil
56
+ end
57
+
58
+ def blank?
59
+ true
60
+ end
61
+
62
+ def present?
63
+ false
64
+ end
52
65
  end
53
66
  end
@@ -0,0 +1,67 @@
1
+ require 'cgi'
2
+ require 'twitter/enumerable'
3
+ require 'twitter/rest/request'
4
+ require 'twitter/utils'
5
+ require 'uri'
6
+
7
+ module Twitter
8
+ class PremiumSearchResults
9
+ include Twitter::Enumerable
10
+ include Twitter::Utils
11
+ # @return [Hash]
12
+ attr_reader :attrs
13
+ alias to_h attrs
14
+ alias to_hash to_h
15
+
16
+ # Initializes a new SearchResults object
17
+ #
18
+ # @param request [Twitter::REST::Request]
19
+ # @return [Twitter::PremiumSearchResults]
20
+ def initialize(request, request_config = {})
21
+ @client = request.client
22
+ @request_method = request.verb
23
+ @path = request.path
24
+ @options = request.options
25
+ @request_config = request_config
26
+ @collection = []
27
+ self.attrs = request.perform
28
+ end
29
+
30
+ private
31
+
32
+ # @return [Boolean]
33
+ def last?
34
+ !next_page?
35
+ end
36
+
37
+ # @return [Boolean]
38
+ def next_page?
39
+ !!@attrs[:next]
40
+ end
41
+
42
+ # Returns a Hash of query parameters for the next result in the search
43
+ #
44
+ # @note Returned Hash can be merged into the previous search options list to easily access the next page.
45
+ # @return [Hash] The parameters needed to fetch the next page.
46
+ def next_page
47
+ {next: @attrs[:next]} if next_page?
48
+ end
49
+
50
+ # @return [Hash]
51
+ def fetch_next_page
52
+ request = @client.premium_search(@options[:query], (@options.reject { |k| k == :query } || {}).merge(next_page), @request_config)
53
+
54
+ self.attrs = request.attrs
55
+ end
56
+
57
+ # @param attrs [Hash]
58
+ # @return [Hash]
59
+ def attrs=(attrs)
60
+ @attrs = attrs
61
+ @attrs.fetch(:results, []).collect do |tweet|
62
+ @collection << Tweet.new(tweet)
63
+ end
64
+ @attrs
65
+ end
66
+ end
67
+ end
@@ -1,17 +1,18 @@
1
1
  require 'addressable/uri'
2
+ require 'cgi'
2
3
  require 'memoizable'
3
4
 
4
5
  module Twitter
5
6
  module Profile
6
- PROFILE_IMAGE_SUFFIX_REGEX = /_normal(\.gif|\.jpe?g|\.png)$/i
7
- PREDICATE_URI_METHOD_REGEX = /_uri\?$/
7
+ PROFILE_IMAGE_SUFFIX_REGEX = /_normal(\.gif|\.jpe?g|\.png)$/i.freeze
8
+ PREDICATE_URI_METHOD_REGEX = /_uri\?$/.freeze
8
9
  include Memoizable
9
10
 
10
11
  class << self
11
12
  private
12
13
 
13
14
  def alias_predicate_uri_methods(method)
14
- %w(_url? _uri_https? _url_https?).each do |replacement|
15
+ %w[_url? _uri_https? _url_https?].each do |replacement|
15
16
  alias_method_sub(method, PREDICATE_URI_METHOD_REGEX, replacement)
16
17
  end
17
18
  end
@@ -88,7 +89,7 @@ module Twitter
88
89
  end
89
90
 
90
91
  def profile_image_suffix(size)
91
- :original == size.to_sym ? '\\1' : "_#{size}\\1"
92
+ size.to_sym == :original ? '\\1' : "_#{size}\\1"
92
93
  end
93
94
  end
94
95
  end
@@ -9,9 +9,8 @@ module Twitter
9
9
  #
10
10
  # @return [Array<Twitter::Size>]
11
11
  def sizes
12
- @attrs.fetch(:sizes, []).inject({}) do |object, (key, value)|
12
+ @attrs.fetch(:sizes, []).each_with_object({}) do |(key, value), object|
13
13
  object[key] = Size.new(value)
14
- object
15
14
  end
16
15
  end
17
16
  memoize :sizes
@@ -7,21 +7,21 @@ module Twitter
7
7
  # @return [Integer]
8
8
  def limit
9
9
  limit = @attrs['x-rate-limit-limit']
10
- limit.to_i if limit
10
+ limit&.to_i
11
11
  end
12
12
  memoize :limit
13
13
 
14
14
  # @return [Integer]
15
15
  def remaining
16
16
  remaining = @attrs['x-rate-limit-remaining']
17
- remaining.to_i if remaining
17
+ remaining&.to_i
18
18
  end
19
19
  memoize :remaining
20
20
 
21
21
  # @return [Time]
22
22
  def reset_at
23
23
  reset = @attrs['x-rate-limit-reset']
24
- Time.at(reset.to_i) if reset
24
+ Time.at(reset.to_i).utc if reset
25
25
  end
26
26
  memoize :reset_at
27
27
 
@@ -0,0 +1,99 @@
1
+ require 'twitter/rest/request'
2
+ require 'twitter/rest/utils'
3
+ require 'twitter/utils'
4
+
5
+ module Twitter
6
+ module REST
7
+ module AccountActivity
8
+ include Twitter::REST::Utils
9
+ include Twitter::Utils
10
+
11
+ # Registers a webhook URL for all event types. The URL will be validated via CRC request before saving. In case the validation failed, returns comprehensive error message to the requester.
12
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference
13
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#post-account-activity-all-env-name-webhooks
14
+ # @note Create a webhook
15
+ # @rate_limited Yes
16
+ # @authentication Requires user context - all consumer and access tokens
17
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
18
+ # @return [Hash]
19
+ # @param env_name [String] Environment Name.
20
+ # @param url [String] Encoded URL for the callback endpoint.
21
+ def create_webhook(env_name, url)
22
+ perform_request(:json_post, "/1.1/account_activity/all/#{env_name}/webhooks.json?url=#{url}")
23
+ end
24
+
25
+ # Returns all environments, webhook URLs and their statuses for the authenticating app. Currently, only one webhook URL can be registered to each environment.
26
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#get-account-activity-all-webhooks
27
+ # @note List webhooks
28
+ # @rate_limited Yes
29
+ # @authentication Requires user context - all consumer and access tokens
30
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
31
+ # @return [Hash]
32
+ # @param env_name [String] Environment Name.
33
+ def list_webhooks(env_name)
34
+ perform_request(:get, "/1.1/account_activity/all/#{env_name}/webhooks.json")
35
+ end
36
+
37
+ # Removes the webhook from the provided application's all activities configuration. The webhook ID can be accessed by making a call to GET /1.1/account_activity/all/webhooks.
38
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#delete-account-activity-all-env-name-webhooks-webhook-id
39
+ # @note Delete a webhook
40
+ # @authentication Requires user context - all consumer and access tokens
41
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
42
+ # @return [nil]
43
+ # @param env_name [String] Environment Name.
44
+ # @param webhook_id [String] Webhook ID.
45
+ def delete_webhook(env_name, webhook_id)
46
+ perform_request(:delete, "/1.1/account_activity/all/#{env_name}/webhooks/#{webhook_id}.json")
47
+ end
48
+
49
+ # Triggers the challenge response check (CRC) for the given enviroments webhook for all activites. If the check is successful, returns 204 and reenables the webhook by setting its status to valid.
50
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#put-account-activity-all-env-name-webhooks-webhook-id
51
+ # @note Trigger CRC check to a webhook
52
+ # @rate_limited Yes
53
+ # @authentication Requires user context - all consumer and access tokens
54
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
55
+ # @return [nil]
56
+ # @param env_name [String] Environment Name.
57
+ # @param webhook_id [String] Webhook ID.
58
+ def trigger_crc_check(env_name, webhook_id)
59
+ perform_request(:json_put, "/1.1/account_activity/all/#{env_name}/webhooks/#{webhook_id}.json")
60
+ end
61
+
62
+ # Subscribes the provided application to all events for the provided environment for all message types. After activation, all events for the requesting user will be sent to the application's webhook via POST request.
63
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#post-account-activity-all-env-name-subscriptions
64
+ # @note Subscribe the user(whose credentials are provided) to the app so that the webhook can receive all types of events from user
65
+ # @rate_limited Yes
66
+ # @authentication Requires user context - all consumer and access tokens
67
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
68
+ # @return [nil]
69
+ # @param env_name [String] Environment Name
70
+ def create_subscription(env_name)
71
+ perform_request(:json_post, "/1.1/account_activity/all/#{env_name}/subscriptions.json")
72
+ end
73
+
74
+ # Provides a way to determine if a webhook configuration is subscribed to the provided user's events. If the provided user context has an active subscription with provided application, returns 204 OK.
75
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#get-account-activity-all-env-name-subscriptions
76
+ # @note Check if the user is subscribed to the given app
77
+ # @rate_limited Yes
78
+ # @authentication Requires user context - all consumer and access tokens
79
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
80
+ # @return [nil]
81
+ # @param env_name [String] Environment Name
82
+ def check_subscription(env_name)
83
+ perform_request(:get, "/1.1/account_activity/all/#{env_name}/subscriptions.json")
84
+ end
85
+
86
+ # Deactivates subscription(s) for the provided user context and application for all activities. After deactivation, all events for the requesting user will no longer be sent to the webhook URL.
87
+ # @see https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/api-reference/aaa-premium#delete-account-activity-all-env-name-subscriptions
88
+ # @note Deactivate a subscription, Users events will not be sent to the app
89
+ # @rate_limited Yes
90
+ # @authentication Requires user context - all consumer and access tokens
91
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
92
+ # @return [nil]
93
+ # @param env_name [String] Environment Name
94
+ def deactivate_subscription(env_name)
95
+ perform_request(:delete, "/1.1/account_activity/all/#{env_name}/subscriptions.json")
96
+ end
97
+ end
98
+ end
99
+ end