Skip to content

Commit

Permalink
Add Twitter::REST::Client#upload
Browse files Browse the repository at this point in the history
  • Loading branch information
sferik committed May 25, 2014
1 parent ed7c708 commit f5a747b
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 2 deletions.
2 changes: 2 additions & 0 deletions lib/twitter/rest/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'twitter/rest/friends_and_followers'
require 'twitter/rest/help'
require 'twitter/rest/lists'
require 'twitter/rest/media'
require 'twitter/rest/oauth'
require 'twitter/rest/places_and_geo'
require 'twitter/rest/saved_searches'
Expand All @@ -23,6 +24,7 @@ module API
include Twitter::REST::FriendsAndFollowers
include Twitter::REST::Help
include Twitter::REST::Lists
include Twitter::REST::Media
include Twitter::REST::OAuth
include Twitter::REST::PlacesAndGeo
include Twitter::REST::SavedSearches
Expand Down
30 changes: 30 additions & 0 deletions lib/twitter/rest/media.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'twitter/error'
require 'twitter/rest/utils'

module Twitter
module REST
module Media
# Uploads media to attach to a tweet
#
# @see https://dev.twitter.com/docs/api/multiple-media-extended-entities
# @rate_limited No
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @raise [Twitter::Error::UnacceptableIO] Error when the IO object for the media argument does not have a to_io method.
# @return [Integer] The uploaded media ID.
# @param media [File, Hash] A File object with your picture (PNG, JPEG or GIF)
# @param options [Hash] A customizable set of options.
# @option options [Boolean, String, Integer] :possibly_sensitive Set to true for content which may not be suitable for every audience.
def upload(media, options = {})
fail(Twitter::Error::UnacceptableIO.new) unless media.respond_to?(:to_io)
url_prefix = 'https://upload.twitter.com'
path = '/1.1/media/upload.json'
conn = connection.dup
conn.url_prefix = url_prefix
headers = request_headers(:post, url_prefix + path, options)
options.merge!(:media => media)
conn.post(path, options) { |request| request.headers.update(headers) }.env.body[:media_id]
end
end
end
end
2 changes: 2 additions & 0 deletions lib/twitter/rest/tweets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def destroy_status(*args)
# @option options [Float] :long The longitude of the location this tweet refers to. The valid ranges for longitude is -180.0 to +180.0 (East is positive) inclusive. This option will be ignored if outside that range, if it is not a number, if geo_enabled is disabled, or if there not a corresponding :lat option.
# @option options [Twitter::Place] :place A place in the world. These can be retrieved from {Twitter::REST::PlacesAndGeo#reverse_geocode}.
# @option options [String] :place_id A place in the world. These IDs can be retrieved from {Twitter::REST::PlacesAndGeo#reverse_geocode}.
# @option options [String] :media_ids A comma separated list of uploaded media IDs to attach to the Tweet.
# @option options [String] :display_coordinates Whether or not to put a pin on the exact coordinates a tweet has been sent from.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def update(status, options = {})
Expand All @@ -147,6 +148,7 @@ def update(status, options = {})
# @option options [Float] :long The longitude of the location this tweet refers to. The valid ranges for longitude is -180.0 to +180.0 (East is positive) inclusive. This option will be ignored if outside that range, if it is not a number, if geo_enabled is disabled, or if there not a corresponding :lat option.
# @option options [Twitter::Place] :place A place in the world. These can be retrieved from {Twitter::REST::PlacesAndGeo#reverse_geocode}.
# @option options [String] :place_id A place in the world. These IDs can be retrieved from {Twitter::REST::PlacesAndGeo#reverse_geocode}.
# @option options [String] :media_ids A comma separated list of uploaded media IDs to attach to the Tweet.
# @option options [String] :display_coordinates Whether or not to put a pin on the exact coordinates a tweet has been sent from.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def update!(status, options = {})
Expand Down
1 change: 1 addition & 0 deletions spec/fixtures/upload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"image":{"w":428,"h":428,"image_type":"image\/png"},"media_id":470030289822314497,"media_id_string":"470030289822314497","size":68900}
54 changes: 54 additions & 0 deletions spec/twitter/rest/media_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'helper'

describe Twitter::REST::Media do
before do
@client = Twitter::REST::Client.new(:consumer_key => 'CK', :consumer_secret => 'CS', :access_token => 'AT', :access_token_secret => 'AS')
end

describe '#upload' do
before do
stub_request(:post, 'https://upload.twitter.com/1.1/media/upload.json').to_return(:body => fixture('upload.json'), :headers => {:content_type => 'application/json; charset=utf-8'})
end
context 'a gif image' do
it 'requests the correct resource' do
@client.upload(fixture('pbjt.gif'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
end
it 'returns an Integer' do
media_id = @client.upload(fixture('pbjt.gif'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
expect(media_id).to be_an Integer
expect(media_id).to eq(470_030_289_822_314_497)
end
end
context 'a jpe image' do
it 'requests the correct resource' do
@client.upload(fixture('wildcomet2.jpe'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
end
end
context 'a jpeg image' do
it 'requests the correct resource' do
@client.upload(fixture('me.jpeg'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
end
end
context 'a png image' do
it 'requests the correct resource' do
@client.upload(fixture('we_concept_bg2.png'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
end
end
context 'a Tempfile' do
it 'requests the correct resource' do
@client.upload(Tempfile.new('tmp'))
expect(a_request(:post, 'https://upload.twitter.com/1.1/media/upload.json')).to have_been_made
end
end
context 'A non IO object' do
it 'raises an error' do
expect { @client.upload('Unacceptable IO') }.to raise_error(Twitter::Error::UnacceptableIO)
end
end
end
end
3 changes: 1 addition & 2 deletions spec/twitter/rest/tweets_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,7 @@
end
context 'A non IO object' do
it 'raises an error' do
update = lambda { @client.update_with_media('You always have options', 'Unacceptable IO') }
expect { update.call }.to raise_error(Twitter::Error::UnacceptableIO)
expect { @client.update_with_media('You always have options', 'Unacceptable IO') }.to raise_error(Twitter::Error::UnacceptableIO)
end
end
context 'already posted' do
Expand Down

0 comments on commit f5a747b

Please sign in to comment.