Module: Twterm::RESTClient

Includes:
Publisher
Included in:
Client
Defined in:
lib/twterm/rest_client.rb

Constant Summary collapse

CONSUMER_KEY =
'vLNSVFgXclBJQJRZ7VLMxL9lA'.freeze
CONSUMER_SECRET =
'OFLKzrepRG2p1hq0nUB9j2S9ndFQoNTPheTpmOY0GYw55jGgS5'.freeze

Instance Method Summary collapse

Methods included from Publisher

#publish

Methods included from Utils

check_type

Instance Method Details

#add_list_member(list_id, user_id) ⇒ Object



12
13
14
# File 'lib/twterm/rest_client.rb', line 12

def add_list_member(list_id, user_id)
  send_request { rest_client.add_list_member(list_id, user_id) }
end

#block(*user_ids) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/twterm/rest_client.rb', line 16

def block(*user_ids)
  send_request do
    rest_client.block(*user_ids)
  end.then do |users|
    users.each do |user|
      friendship_repository.block(self.user_id, user.id)
    end
  end
end

#destroy_status(status) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/twterm/rest_client.rb', line 26

def destroy_status(status)
  send_request_without_catch do
    rest_client.destroy_status(status.id)
    publish(Event::Status::Delete.new(status.id))
    publish(Event::Message::Success.new('Your tweet has been deleted'))
  end.catch do |reason|
    case reason
    when Twitter::Error::NotFound, Twitter::Error::Forbidden
      publish(Event::Message::Error.new('You cannot destroy that status'))
    else
      raise reason
    end
  end.catch(&show_error)
end

#favorite(status) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/twterm/rest_client.rb', line 41

def favorite(status)
  return false unless status.is_a? Status

  send_request do
    rest_client.favorite(status.id)
  end.then do |tweet, *_|
    status_repository.create(tweet)

    publish(Event::Message::Success.new('Successfully liked: @%s "%s"' % [
      tweet.user.screen_name, status.text
    ]))
  end
end

#favorites(user_id = nil) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/twterm/rest_client.rb', line 55

def favorites(user_id = nil)
  user_id ||= self.user_id

  send_request do
    rest_client.favorites(user_id, count: 200, tweet_mode: :extended)
  end.then do |tweets|
    tweets.map { |tweet| status_repository.create(tweet) }
  end
end

#fetch_muted_usersObject



65
66
67
68
69
# File 'lib/twterm/rest_client.rb', line 65

def fetch_muted_users
  send_request do
    @muted_user_ids = rest_client.muted_ids.to_a
  end
end

#follow(*user_ids) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/twterm/rest_client.rb', line 71

def follow(*user_ids)
  send_request do
    rest_client.follow(*user_ids)
  end.then do |users|
    users.each do |user|
      if user.protected?
        friendship_repository.following_requested(self.user_id, user.id)
      else
        friendship_repository.follow(self.user_id, user.id)
      end
    end
  end
end

#followers(user_id = nil) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/twterm/rest_client.rb', line 85

def followers(user_id = nil)
  user_id ||= self.user_id

  m = Mutex.new

  send_request do
    rest_client.follower_ids(user_id).each_slice(100) do |user_ids|
      m.synchronize do
        users = rest_client.users(*user_ids).map { |u| user_repository.create(u) }
        users.each do |user|
          friendship_repository.follow(user.id, self.user_id)
        end if user_id == self.user_id
        yield users
      end
    end
  end
end

#friends(user_id = nil) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/twterm/rest_client.rb', line 103

def friends(user_id = nil)
  user_id ||= self.user_id

  m = Mutex.new

  send_request do
    rest_client.friend_ids(user_id).each_slice(100) do |user_ids|
      m.synchronize do
        yield rest_client.users(*user_ids).map { |u| user_repository.create(u) }
      end
    end
  end
end

#home_timelineObject



117
118
119
120
121
122
123
124
125
# File 'lib/twterm/rest_client.rb', line 117

def home_timeline
  send_request do
    rest_client.home_timeline(count: 200, tweet_mode: :extended)
  end.then do |tweets|
    tweets
    .select(&@mute_filter)
    .map { |tweet| status_repository.create(tweet) }
  end
end

#list(list_id) ⇒ Object



127
128
129
130
131
132
133
# File 'lib/twterm/rest_client.rb', line 127

def list(list_id)
  send_request do
    rest_client.list(list_id)
  end.then do |list|
    list_repository.create(list)
  end
end

#list_timeline(list_id) ⇒ Object



135
136
137
138
139
140
141
142
143
# File 'lib/twterm/rest_client.rb', line 135

def list_timeline(list_id)
  send_request do
    rest_client.list_timeline(list_id, count: 200, tweet_mode: :extended)
  end.then do |statuses|
    statuses
    .select(&@mute_filter)
    .map { |tweet| status_repository.create(tweet) }
  end
end

#listsObject



145
146
147
148
149
150
151
# File 'lib/twterm/rest_client.rb', line 145

def lists
  send_request do
    rest_client.lists
  end.then do |lists|
    lists.map { |list| list_repository.create(list) }
  end
end

#lookup_friendshipsObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/twterm/rest_client.rb', line 153

def lookup_friendships
  repo = friendship_repository
  user_ids = user_repository.ids.reject { |id| repo.already_looked_up?(id) }
  send_request_without_catch do
    user_ids.each_slice(100) do |chunked_user_ids|
      friendships = rest_client.friendships(*chunked_user_ids)
      friendships.each do |friendship|
        id = friendship.id
        client_id = user_id

        conn = friendship.connections
        conn.include?('blocking') ? repo.block(client_id, id) : repo.unblock(client_id, id)
        conn.include?('following') ? repo.follow(client_id, id) : repo.unfollow(client_id, id)
        conn.include?('following_requested') ? repo.following_requested(client_id, id) : repo.following_not_requested(client_id, id)
        conn.include?('followed_by') ? repo.follow(id, client_id) : repo.unfollow(id, client_id)
        conn.include?('muting') ? repo.mute(client_id, id) : repo.unmute(client_id, id)

        repo.looked_up!(id)
      end
    end
  end.catch do |e|
    case e
    when Twitter::Error::TooManyRequests # rubocop:disable Lint/EmptyWhen
      # do nothing
    else
      raise e
    end
  end.catch(&show_error)
end

#memberships(user_id, options = {}) ⇒ Object



183
184
185
186
187
188
189
# File 'lib/twterm/rest_client.rb', line 183

def memberships(user_id, options = {})
  send_request do
    user_id.nil? ? rest_client.memberships(options) : rest_client.memberships(user_id, options)
  end.then do |cursor|
    cursor.map { |list| list_repository.create(list) }
  end
end

#mentionsObject



191
192
193
194
195
196
197
198
199
# File 'lib/twterm/rest_client.rb', line 191

def mentions
  send_request do
    rest_client.mentions(count: 200, tweet_mode: :extended)
  end.then do |statuses|
    statuses
    .select(&@mute_filter)
    .map { |tweet| status_repository.create(tweet) }
  end
end

#mute(user_ids) ⇒ Object



201
202
203
204
205
206
207
208
209
# File 'lib/twterm/rest_client.rb', line 201

def mute(user_ids)
  send_request do
    rest_client.mute(*user_ids)
  end.then do |users|
    users.each do |user|
      friendship_repository.mute(self.user_id, user.id)
    end
  end
end

#owned_listsObject



211
212
213
214
215
216
217
# File 'lib/twterm/rest_client.rb', line 211

def owned_lists
  send_request do
    rest_client.owned_lists
  end.then do |lists|
    lists.map { |list| list_repository.create(list) }
  end
end

#post(text, options = {}) ⇒ Object



219
220
221
222
223
224
225
226
227
228
# File 'lib/twterm/rest_client.rb', line 219

def post(text, options = {})
  send_request do
    rest_client.update(text, options)
  end
    .then do |status|
      publish(Event::Message::Success.new('Your tweet has been posted'))

      status
    end
end

#rate_limit_statusObject



230
231
232
# File 'lib/twterm/rest_client.rb', line 230

def rate_limit_status
  send_request { Twitter::REST::Request.new(rest_client, :get, '/1.1/application/rate_limit_status.json').perform }
end

#remove_list_member(list_id, user_id) ⇒ Object



234
235
236
# File 'lib/twterm/rest_client.rb', line 234

def remove_list_member(list_id, user_id)
  send_request { rest_client.remove_list_member(list_id, user_id) }
end

#rest_clientObject



379
380
381
382
383
384
385
386
# File 'lib/twterm/rest_client.rb', line 379

def rest_client
  @rest_client ||= Twitter::REST::Client.new do |config|
    config.consumer_key        = CONSUMER_KEY
    config.consumer_secret     = CONSUMER_SECRET
    config.access_token        = @access_token
    config.access_token_secret = @access_token_secret
  end
end

#retweet(status) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/twterm/rest_client.rb', line 238

def retweet(status)
  fail ArgumentError,
    'argument must be an instance of Status class' unless status.is_a? Status

  send_request_without_catch do
    rest_client.retweet!(status.id)
  end.then do |tweet, *_|
    status_repository.create(tweet)

    publish(Event::Message::Success.new('Successfully retweeted: @%s "%s"' % [
      tweet.user.screen_name, status.text
    ]))
  end.catch do |reason|
    message =
      case reason
      when Twitter::Error::AlreadyRetweeted
        'The status is already retweeted'
      when Twitter::Error::NotFound
        'The status is not found'
      when Twitter::Error::Forbidden
        'The status is protected'
      else
        raise e
      end
    publish(Event::Message::Error.new("Retweet attempt failed: #{message}"))
  end.catch(&show_error)
end

#saved_searchObject



266
267
268
269
270
# File 'lib/twterm/rest_client.rb', line 266

def saved_search
  send_request do
    rest_client.saved_searches
  end
end

#search(query) ⇒ Object



272
273
274
275
276
277
278
279
280
# File 'lib/twterm/rest_client.rb', line 272

def search(query)
  send_request do
    rest_client.search(query, count: 100, tweet_mode: :extended).attrs[:statuses]
  end.then do |statuses|
    statuses
    .map(&Twitter::Tweet.method(:new))
    .map { |tweet| status_repository.create(tweet) }
  end
end

#send_request(&block) ⇒ Object



388
389
390
# File 'lib/twterm/rest_client.rb', line 388

def send_request(&block)
  send_request_without_catch(&block).catch(&show_error)
end

#send_request_without_catch(&block) ⇒ Object



392
393
394
# File 'lib/twterm/rest_client.rb', line 392

def send_request_without_catch(&block)
  Concurrent::Promise.execute { block.call }
end

#show_status(status_id) ⇒ Object



282
283
284
285
286
287
288
# File 'lib/twterm/rest_client.rb', line 282

def show_status(status_id)
  send_request do
    rest_client.status(status_id)
  end.then do |status|
    status_repository.create(status)
  end
end

#show_user(query) ⇒ Object



290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/twterm/rest_client.rb', line 290

def show_user(query)
  send_request_without_catch do
    rest_client.user(query)
  end.catch do |reason|
    case reason
    when Twitter::Error::NotFound
      nil
    else
      raise reason
    end
  end.catch(&show_error).then do |user|
    user.nil? ? nil : user_repository.create(user)
  end
end

#unblock(*user_ids) ⇒ Object



305
306
307
308
309
310
311
312
313
# File 'lib/twterm/rest_client.rb', line 305

def unblock(*user_ids)
  send_request do
    rest_client.unblock(*user_ids)
  end.then do |users|
    users.each do |user|
      friendship_repository.unblock(self.user_id, user.id)
    end
  end
end

#unfavorite(status) ⇒ Object



315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/twterm/rest_client.rb', line 315

def unfavorite(status)
  fail ArgumentError,
    'argument must be an instance of Status class' unless status.is_a? Status

  send_request do
    rest_client.unfavorite(status.id)
  end.then do |tweet, *_|
    status_repository.create(tweet)

    publish(Event::Message::Success.new("Successfully unliked @#{tweet.user.screen_name}'s tweet", sutatus.text))
  end
end

#unfollow(*user_ids) ⇒ Object



328
329
330
331
332
333
334
335
336
# File 'lib/twterm/rest_client.rb', line 328

def unfollow(*user_ids)
  send_request do
    rest_client.unfollow(*user_ids)
  end.then do |users|
    users.each do |user|
      friendship_repository.unfollow(self.user_id, user.id)
    end
  end
end

#unmute(user_ids) ⇒ Object



338
339
340
341
342
343
344
345
346
# File 'lib/twterm/rest_client.rb', line 338

def unmute(user_ids)
  send_request do
    rest_client.unmute(*user_ids)
  end.then do |users|
    users.each do |user|
      friendship_repository.unmute(self.user_id, user.id)
    end
  end
end

#unretweet(status) ⇒ Object



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/twterm/rest_client.rb', line 348

def unretweet(status)
  send_request do
    Twitter::REST::Request.new(rest_client, :post, "/1.1/statuses/unretweet/#{status.id}.json").perform
  end
    .then do |json, *_|
      json[:retweet_count] -= 1
      json[:retweeted] = false

      Twitter::Tweet.new(json)
    end
    .then do |tweet|
      status = status_repository.create(tweet)

      publish(Event::Message::Success.new('Successfully unretweeted: @%s "%s"' % [
        tweet.user.screen_name, status.text
      ]))

      status
    end
end

#user_timeline(user_id) ⇒ Object



369
370
371
372
373
374
375
376
377
# File 'lib/twterm/rest_client.rb', line 369

def user_timeline(user_id)
  send_request do
    rest_client.user_timeline(user_id, count: 200)
  end.then do |statuses|
    statuses
    .select(&@mute_filter)
    .map { |tweet| status_repository.create(tweet) }
  end
end