diff --git a/lib/twitter/cursor.rb b/lib/twitter/cursor.rb index 2938333d1..0500365ae 100644 --- a/lib/twitter/cursor.rb +++ b/lib/twitter/cursor.rb @@ -32,12 +32,14 @@ def initialize(key, klass, request) # @return [Integer] def next_cursor - @attrs[:next_cursor] || -1 + @attrs[:next_cursor] end alias next next_cursor # @return [Boolean] def last? + return false if next_cursor.is_a?(String) + return true if next_cursor.nil? next_cursor.zero? end diff --git a/lib/twitter/direct_message.rb b/lib/twitter/direct_message.rb index 7f6272c50..e30ab3d41 100644 --- a/lib/twitter/direct_message.rb +++ b/lib/twitter/direct_message.rb @@ -8,6 +8,8 @@ class DirectMessage < Twitter::Identity include Twitter::Entities # @return [String] attr_reader :text + attr_reader :sender_id + attr_reader :recipient_id alias full_text text object_attr_reader :User, :recipient object_attr_reader :User, :sender diff --git a/lib/twitter/direct_message_event.rb b/lib/twitter/direct_message_event.rb new file mode 100644 index 000000000..99aca16d5 --- /dev/null +++ b/lib/twitter/direct_message_event.rb @@ -0,0 +1,38 @@ +require 'twitter/creatable' +require 'twitter/entities' +require 'twitter/identity' + +module Twitter + class DirectMessageEvent < Twitter::Identity + include Twitter::Creatable + include Twitter::Entities + + attr_reader :created_timestamp + + object_attr_reader :DirectMessage, :direct_message + + def initialize(attrs) + text = attrs[:message_create][:message_data][:text] + urls = attrs[:message_create][:message_data][:entities][:urls] + + text.gsub!(urls[0][:url], urls[0][:expanded_url]) if urls.any? + + attrs[:direct_message] = build_direct_message(attrs, text) + super + end + + private + + def build_direct_message(attrs, text) + recipient_id = attrs[:message_create][:target][:recipient_id].to_i + sender_id = attrs[:message_create][:sender_id].to_i + {id: attrs[:id].to_i, + created_at: Time.at(attrs[:created_timestamp].to_i / 1000.0), + sender: {id: sender_id}, + sender_id: sender_id, + recipient: {id: recipient_id}, + recipient_id: recipient_id, + text: text} + end + end +end diff --git a/lib/twitter/rest/direct_messages.rb b/lib/twitter/rest/direct_messages.rb index ffc2880a4..b3fd31544 100644 --- a/lib/twitter/rest/direct_messages.rb +++ b/lib/twitter/rest/direct_messages.rb @@ -1,5 +1,6 @@ require 'twitter/arguments' require 'twitter/direct_message' +require 'twitter/direct_message_event' require 'twitter/rest/utils' require 'twitter/user' require 'twitter/utils' @@ -27,6 +28,20 @@ def direct_messages_received(options = {}) perform_get_with_objects('/1.1/direct_messages.json', options, Twitter::DirectMessage) end + # Returns the 20 most recent direct messages events sent to the authenticating user + # @see https://dev.twitter.com/rest/reference/get/direct_messages/events/list + # @note This method requires an access token with RWD (read, write & direct message) permissions. Consult The Application Permission Model for more information. + # @rate_limited Yes + # @authentication Requires user context + # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid. + # @return [Array] Direct messages sent to and received by the authenticating user. + # @param options [Hash] A customizable set of options. + # @option options [Integer] :count Specifies the number of records to retrieve. Must be less than or equal to 50. Default is 20 + # @option options [String] :cursor Specifies the cursor position of results to retrieve. + def direct_messages_events(options = {}) + perform_get_with_cursor('/1.1/direct_messages/events/list.json', options.merge!(no_default_cursor: true), :events, Twitter::DirectMessageEvent) + end + # Returns the 20 most recent direct messages sent by the authenticating user # # @see https://dev.twitter.com/rest/reference/get/direct_messages/sent diff --git a/lib/twitter/rest/utils.rb b/lib/twitter/rest/utils.rb index e254f599c..b475672fc 100644 --- a/lib/twitter/rest/utils.rb +++ b/lib/twitter/rest/utils.rb @@ -102,7 +102,12 @@ def perform_request_with_objects(request_method, path, options, klass) # @param collection_name [Symbol] # @param klass [Class] def perform_get_with_cursor(path, options, collection_name, klass = nil) - merge_default_cursor!(options) + if options[:no_default_cursor] + options.delete(:no_default_cursor) + else + merge_default_cursor!(options) + end + request = Twitter::REST::Request.new(self, :get, path, options) Twitter::Cursor.new(collection_name.to_sym, klass, request) end diff --git a/spec/fixtures/events.json b/spec/fixtures/events.json new file mode 100644 index 000000000..6c3131f48 --- /dev/null +++ b/spec/fixtures/events.json @@ -0,0 +1 @@ +{"events":[{"type":"message_create","id":"856574281366605831","created_timestamp":"1493058197715","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"358486183","message_data":{"text":"Thanks https://t.co/ZxBEw35k5z","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/ZxBEw35k5z","expanded_url":"https://twitter.com/i/stickers/image/10011","display_url":"twitter.com/i/stickers/ima…","indices":[1,24]}]}}}},{"type":"message_create","id":"856571192978927619","created_timestamp":"1493057461386","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"311650899","message_data":{"text":"❤️","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856554872984018948","created_timestamp":"1493053570396","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"422190131","message_data":{"text":"😍","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856538753409703939","created_timestamp":"1493049727190","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"759849327200047104","message_data":{"text":"obrigada!!! bj","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856533644445396996","created_timestamp":"1493048509118","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"73660881","message_data":{"text":" https://t.co/ZxBEw35k5z","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/ZxBEw35k5z","expanded_url":"https://twitter.com/i/stickers/image/10011","display_url":"twitter.com/i/stickers/ima…","indices":[1,24]}]}}}},{"type":"message_create","id":"856526573545062407","created_timestamp":"1493046823284","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"328677087","message_data":{"text":"OBRIGADO MINHA LINDA SERÁ INCRÍVEL ASSISTIR O TEU SHOW, VOU FAZER O POSSÍVEL PARA TE PRESTIGIAR. SUCESSO","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856523843892129796","created_timestamp":"1493046172484","message_create":{"target":{"recipient_id":"422190131"},"sender_id":"22095868","message_data":{"text":" https://t.co/KQcQAF6hVS","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/KQcQAF6hVS","expanded_url":"https://twitter.com/i/stickers/image/10018","display_url":"twitter.com/i/stickers/ima…","indices":[1,24]}]}}}},{"type":"message_create","id":"856523768910544899","created_timestamp":"1493046154607","message_create":{"target":{"recipient_id":"4374876088"},"sender_id":"22095868","message_data":{"text":" https://t.co/MG2QdVuPGa","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/MG2QdVuPGa","expanded_url":"https://twitter.com/i/stickers/image/10017","display_url":"twitter.com/i/stickers/ima…","indices":[1,24]}]}}}},{"type":"message_create","id":"856516885524951043","created_timestamp":"1493044513480","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"4374876088","message_data":{"text":"Obrigado. Vou adquiri-lo. Muito sucesso!","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856502352299405315","created_timestamp":"1493041048489","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"422190131","message_data":{"text":"COM CERTEZA QDO ESTIVER EM SAO PAUÇO IREI COM O MAIOR PRAZER SUCESSO LINDA","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856480385957548035","created_timestamp":"1493035811305","message_create":{"target":{"recipient_id":"2924245126"},"sender_id":"22095868","message_data":{"text":"Obrigada Jacques","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856480124421771268","created_timestamp":"1493035748950","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"2924245126","message_data":{"text":"😍 Música boa para seu espetáculo em São-Paulo com seu amigo","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856478933260410883","created_timestamp":"1493035464955","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"2924245126","message_data":{"text":"Jardim urbano","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856478621090942979","created_timestamp":"1493035390528","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"2924245126","message_data":{"text":" https://t.co/1ojXzm8bKx","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/1ojXzm8bKx","expanded_url":"https://twitter.com/messages/media/856478621090942979","display_url":"pic.twitter.com/1ojXzm8bKx","indices":[1,24]}]},"attachment":{"type":"media","media":{"id":856478542527385601,"id_str":"856478542527385601","indices":[1,24],"media_url":"https://ton.twitter.com/1.1/ton/data/dm/856478621090942979/856478542527385601/d3LfgVMN.jpg","media_url_https":"https://ton.twitter.com/1.1/ton/data/dm/856478621090942979/856478542527385601/d3LfgVMN.jpg","url":"https://t.co/1ojXzm8bKx","display_url":"pic.twitter.com/1ojXzm8bKx","expanded_url":"https://twitter.com/messages/media/856478621090942979","type":"photo","sizes":{"small":{"w":340,"h":255,"resize":"fit"},"medium":{"w":600,"h":450,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"large":{"w":997,"h":748,"resize":"fit"}}}}}}},{"type":"message_create","id":"856477958885834755","created_timestamp":"1493035232646","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"2924245126","message_data":{"text":"Os amantes em face a o mar","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[]}}}},{"type":"message_create","id":"856477710595624963","created_timestamp":"1493035173449","message_create":{"target":{"recipient_id":"22095868"},"sender_id":"2924245126","message_data":{"text":" https://t.co/RrE2qo9upr","entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https://t.co/RrE2qo9upr","expanded_url":"https://twitter.com/messages/media/856477710595624963","display_url":"pic.twitter.com/RrE2qo9upr","indices":[1,24]}]},"attachment":{"type":"media","media":{"id":856477689447841792,"id_str":"856477689447841792","indices":[1,24],"media_url":"https://ton.twitter.com/1.1/ton/data/dm/856477710595624963/856477689447841792/i3ViseFg.jpg","media_url_https":"https://ton.twitter.com/1.1/ton/data/dm/856477710595624963/856477689447841792/i3ViseFg.jpg","url":"https://t.co/RrE2qo9upr","display_url":"pic.twitter.com/RrE2qo9upr","expanded_url":"https://twitter.com/messages/media/856477710595624963","type":"photo","sizes":{"small":{"w":340,"h":453,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"large":{"w":502,"h":669,"resize":"fit"},"medium":{"w":502,"h":669,"resize":"fit"}}}}}}}],"next_cursor":"ODU2NDc3NzEwNTk1NjI0OTYz"} diff --git a/spec/fixtures/ids_list_new_cursor.json b/spec/fixtures/ids_list_new_cursor.json new file mode 100644 index 000000000..41333b513 --- /dev/null +++ b/spec/fixtures/ids_list_new_cursor.json @@ -0,0 +1 @@ +{"previous_cursor":0,"next_cursor_str":"1305102810874389703","ids":[20009713,22469930,351223419],"previous_cursor_str":"0","next_cursor":"ODU2NDc3NzEwNTk1NjI0OTYz"} diff --git a/spec/fixtures/ids_list_new_cursor2.json b/spec/fixtures/ids_list_new_cursor2.json new file mode 100644 index 000000000..35d1eef63 --- /dev/null +++ b/spec/fixtures/ids_list_new_cursor2.json @@ -0,0 +1 @@ +{"ids":[20009713,22469930,351223419]} diff --git a/spec/twitter/cursor_spec.rb b/spec/twitter/cursor_spec.rb index 9e0f87df3..3d3490b20 100644 --- a/spec/twitter/cursor_spec.rb +++ b/spec/twitter/cursor_spec.rb @@ -25,4 +25,31 @@ end end end + + describe '#cursor new format' do + before do + @client = Twitter::REST::Client.new(consumer_key: 'CK', consumer_secret: 'CS', access_token: 'AT', access_token_secret: 'AS') + stub_get('/1.1/followers/ids.json').with(query: {cursor: '-1', screen_name: 'sferik'}).to_return(body: fixture('ids_list_new_cursor.json'), headers: {content_type: 'application/json; charset=utf-8'}) + stub_get('/1.1/followers/ids.json').with(query: {cursor: 'ODU2NDc3NzEwNTk1NjI0OTYz', screen_name: 'sferik'}).to_return(body: fixture('ids_list_new_cursor2.json'), headers: {content_type: 'application/json; charset=utf-8'}) + end + + it 'requests the correct resources' do + @client.follower_ids('sferik').each {} + expect(a_get('/1.1/followers/ids.json').with(query: {cursor: '-1', screen_name: 'sferik'})).to have_been_made + expect(a_get('/1.1/followers/ids.json').with(query: {cursor: 'ODU2NDc3NzEwNTk1NjI0OTYz', screen_name: 'sferik'})).to have_been_made + end + + it 'iterates' do + count = 0 + @client.follower_ids('sferik').each { count += 1 } + expect(count).to eq(6) + end + context 'with start' do + it 'iterates' do + count = 0 + @client.follower_ids('sferik').each(5) { count += 1 } + expect(count).to eq(1) + end + end + end end diff --git a/spec/twitter/rest/direct_messages_spec.rb b/spec/twitter/rest/direct_messages_spec.rb index 8b3dfce8a..eb1874a5d 100644 --- a/spec/twitter/rest/direct_messages_spec.rb +++ b/spec/twitter/rest/direct_messages_spec.rb @@ -21,6 +21,30 @@ end end + describe '#direct_messages_events' do + before do + stub_get('/1.1/direct_messages/events/list.json').to_return(body: fixture('events.json'), headers: {content_type: 'application/json; charset=utf-8'}) + end + + it 'requests the correct resource' do + @client.direct_messages_events + expect(a_get('/1.1/direct_messages/events/list.json')).to have_been_made + end + + it 'returns messages' do + direct_messages = @client.direct_messages_events + + expect(direct_messages).to be_a Twitter::Cursor + expect(direct_messages.first).to be_a Twitter::DirectMessageEvent + expect(direct_messages.first.id).to eq('856574281366605831') + expect(direct_messages.first.created_timestamp).to eq('1493058197715') + expect(direct_messages.first.direct_message.text).to eq('Thanks https://twitter.com/i/stickers/image/10011') + expect(direct_messages.first.direct_message.sender_id).to eq(358_486_183) + expect(direct_messages.first.direct_message.recipient_id).to eq(22_095_868) + expect(direct_messages.first.direct_message.sender.id).to eq(358_486_183) + expect(direct_messages.first.direct_message.recipient.id).to eq(22_095_868) + end + end describe '#direct_messages_sent' do before do stub_get('/1.1/direct_messages/sent.json').to_return(body: fixture('direct_messages.json'), headers: {content_type: 'application/json; charset=utf-8'})