[deploy] Decouple Twitter authentication from fetching tweets (#7920)
* Add TwitterClient::Client * Use TwitterClient::Client for Tweet * Test retweets * Test assignment to user * Fix TweetTag spec * Remove TwitterBot * Fix some specs * Fix RSS Reader specs
This commit is contained in:
parent
59765d339f
commit
300ba1b33f
34 changed files with 6414 additions and 172 deletions
10
Envfile
10
Envfile
|
|
@ -46,15 +46,15 @@ variable :FORCE_SSL_IN_RAILS, :String, default: "not applicable in dev"
|
|||
# It's best if you have the following configured
|
||||
# for more development experience
|
||||
|
||||
# Github for github related access
|
||||
# GitHub
|
||||
# (https://developer.github.com/v3/guides/basics-of-authentication/)
|
||||
variable :GITHUB_KEY, :String, default: ""
|
||||
variable :GITHUB_SECRET, :String, default: ""
|
||||
|
||||
# Twitter for normal twitter access
|
||||
# (https://developer.twitter.com/en/docs/basics/authentication/guides/access-tokens)
|
||||
variable :TWITTER_KEY, :String, default: "Optional"
|
||||
variable :TWITTER_SECRET, :String, default: "Optional"
|
||||
# Twitter
|
||||
# (https://developer.twitter.com/en/docs/basics/authentication/oauth-2-0/application-only)
|
||||
variable :TWITTER_KEY, :String, default: ""
|
||||
variable :TWITTER_SECRET, :String, default: ""
|
||||
|
||||
################################################
|
||||
######### Optional 3rd Party Services ##########
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
class TwitterBot
|
||||
def self.client(token:, secret:)
|
||||
Twitter::REST::Client.new do |config|
|
||||
config.consumer_key = ApplicationConfig["TWITTER_KEY"]
|
||||
config.consumer_secret = ApplicationConfig["TWITTER_SECRET"]
|
||||
config.access_token = token
|
||||
config.access_token_secret = secret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3,32 +3,15 @@ class Tweet < ApplicationRecord
|
|||
|
||||
belongs_to :user, optional: true
|
||||
|
||||
serialize :mentioned_usernames_serialized
|
||||
serialize :hashtags_serialized
|
||||
serialize :urls_serialized
|
||||
serialize :media_serialized
|
||||
serialize :extended_entities_serialized
|
||||
serialize :full_fetched_object_serialized
|
||||
serialize :hashtags_serialized
|
||||
serialize :media_serialized
|
||||
serialize :mentioned_usernames_serialized
|
||||
serialize :urls_serialized
|
||||
|
||||
validates :twitter_id_code, presence: true
|
||||
validates :full_fetched_object_serialized, presence: true
|
||||
|
||||
def self.find_or_fetch(twitter_id_code)
|
||||
find_by(twitter_id_code: twitter_id_code) || fetch(twitter_id_code)
|
||||
end
|
||||
|
||||
def self.fetch(twitter_id_code)
|
||||
tries = 0
|
||||
tweet = nil
|
||||
until tries > 4 || tweet
|
||||
begin
|
||||
return tweet = try_to_get_tweet(twitter_id_code)
|
||||
rescue StandardError => e
|
||||
Rails.logger.error(e)
|
||||
tries += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
validates :twitter_id_code, presence: true
|
||||
|
||||
def processed_text
|
||||
urls_serialized.each do |url|
|
||||
|
|
@ -55,66 +38,83 @@ class Tweet < ApplicationRecord
|
|||
end
|
||||
|
||||
class << self
|
||||
def try_to_get_tweet(twitter_id_code)
|
||||
client = TwitterBot.client(random_identity)
|
||||
tweet = client.status(twitter_id_code, tweet_mode: "extended")
|
||||
make_tweet_from_api_object(tweet)
|
||||
def find_or_fetch(status_id)
|
||||
find_by(twitter_id_code: status_id) || fetch(status_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def make_tweet_from_api_object(tweeted)
|
||||
tweeted = if tweeted.attrs[:retweeted_status]
|
||||
TwitterBot.client(random_identity).status(tweeted.attrs[:retweeted_status][:id_str])
|
||||
else
|
||||
tweeted
|
||||
end
|
||||
def fetch(status_id)
|
||||
retrieve_and_save_tweet(status_id)
|
||||
rescue TwitterClient::Errors::NotFound => e
|
||||
raise e, "Tweet not found"
|
||||
end
|
||||
|
||||
tweet = Tweet.where(twitter_id_code: tweeted.attrs[:id_str]).first_or_initialize
|
||||
def retrieve_and_save_tweet(status_id)
|
||||
status = TwitterClient::Client.status(status_id, tweet_mode: "extended")
|
||||
create_tweet_from_api_status(status)
|
||||
end
|
||||
|
||||
def create_tweet_from_api_status(status)
|
||||
status = if status.retweeted_status.present?
|
||||
TwitterClient::Client.status(status.retweeted_status.id.to_s)
|
||||
else
|
||||
status
|
||||
end
|
||||
|
||||
params = { twitter_id_code: status.id.to_s }
|
||||
tweet = Tweet.find_by(params) || new(params)
|
||||
|
||||
tweet.text = status.full_text
|
||||
|
||||
# matching the retrieved tweet to the DB user if there is one
|
||||
tweet.user_id = User.find_by(twitter_username: status.user.screen_name)&.id
|
||||
|
||||
tweet = extract_metadata_attributes(tweet, status)
|
||||
tweet = extract_serializable_attributes(tweet, status)
|
||||
tweet = extract_user_attributes(tweet, status)
|
||||
|
||||
tweet.twitter_uid = tweeted.user.id.to_s
|
||||
tweet.twitter_username = tweeted.user.screen_name.downcase
|
||||
tweet.user_id = User.find_by(twitter_username: tweeted.user.screen_name)&.id
|
||||
tweet.favorite_count = tweeted.favorite_count
|
||||
tweet.retweet_count = tweeted.retweet_count
|
||||
tweet.twitter_user_following_count = tweeted.user.friends_count
|
||||
tweet.twitter_user_followers_count = tweeted.user.followers_count
|
||||
tweet.in_reply_to_username = tweeted.in_reply_to_screen_name
|
||||
tweet.source = tweeted.source
|
||||
tweet.twitter_name = tweeted.user.name
|
||||
tweet.mentioned_usernames_serialized = tweeted.user_mentions.as_json
|
||||
tweet.remote_profile_image_url = tweeted.user.profile_image_url
|
||||
tweet.last_fetched_at = Time.current
|
||||
tweet.user_is_verified = tweeted.user.verified?
|
||||
tweet = handle_tweeted_attrs(tweet, tweeted)
|
||||
|
||||
tweet.save!
|
||||
|
||||
tweet
|
||||
end
|
||||
|
||||
def handle_tweeted_attrs(tweet, tweeted)
|
||||
tweet.in_reply_to_user_id_code = tweeted.attrs[:in_reply_to_user_id_str]
|
||||
tweet.in_reply_to_status_id_code = tweeted.attrs[:in_reply_to_status_id_str]
|
||||
tweet.twitter_id_code = tweeted.attrs[:id_str]
|
||||
tweet.quoted_tweet_id_code = tweeted.attrs[:quoted_status_id_str]
|
||||
tweet.text = tweeted.attrs[:full_text]
|
||||
tweet.hashtags_serialized = tweeted.attrs[:entities][:hashtags]
|
||||
tweet.urls_serialized = tweeted.attrs[:entities][:urls]
|
||||
tweet.media_serialized = tweeted.attrs[:media]
|
||||
tweet.extended_entities_serialized = tweeted.attrs[:extended_entities]
|
||||
tweet.full_fetched_object_serialized = tweeted.attrs
|
||||
tweet.tweeted_at = tweeted.attrs[:created_at]
|
||||
tweet.is_quote_status = tweeted.attrs[:is_quote_status]
|
||||
def extract_metadata_attributes(tweet, status)
|
||||
tweet.favorite_count = status.favorite_count
|
||||
tweet.in_reply_to_status_id_code = status.in_reply_to_status_id.to_s
|
||||
tweet.in_reply_to_user_id_code = status.in_reply_to_user_id.to_s
|
||||
tweet.in_reply_to_username = status.in_reply_to_screen_name.to_s
|
||||
tweet.is_quote_status = status.attrs[:is_quote_status]
|
||||
tweet.quoted_tweet_id_code = status.attrs[:quoted_status_id_str]
|
||||
tweet.retweet_count = status.retweet_count
|
||||
tweet.source = status.source
|
||||
tweet.tweeted_at = status.created_at
|
||||
|
||||
tweet
|
||||
end
|
||||
|
||||
def random_identity
|
||||
iden = Identity.where(provider: "twitter").last(250).sample
|
||||
{
|
||||
token: iden&.token || ApplicationConfig["TWITTER_KEY"],
|
||||
secret: iden&.secret || ApplicationConfig["TWITTER_SECRET"]
|
||||
}
|
||||
def extract_serializable_attributes(tweet, status)
|
||||
tweet.extended_entities_serialized = status.attrs[:extended_entities]
|
||||
tweet.full_fetched_object_serialized = status.attrs
|
||||
tweet.hashtags_serialized = status.hashtags
|
||||
tweet.media_serialized = status.attrs.dig(:entities, :media)
|
||||
tweet.mentioned_usernames_serialized = status.user_mentions.as_json
|
||||
tweet.urls_serialized = status.urls
|
||||
|
||||
tweet
|
||||
end
|
||||
|
||||
def extract_user_attributes(tweet, status)
|
||||
tweet.remote_profile_image_url = status.user.profile_image_url
|
||||
tweet.twitter_name = status.user.name
|
||||
tweet.twitter_uid = status.user.id.to_s
|
||||
tweet.twitter_user_followers_count = status.user.followers_count
|
||||
tweet.twitter_user_following_count = status.user.friends_count
|
||||
tweet.twitter_username = status.user.screen_name.downcase
|
||||
tweet.user_is_verified = status.user.verified?
|
||||
|
||||
tweet
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,12 +4,17 @@ class RssReader
|
|||
end
|
||||
|
||||
def get_all_articles(force = true)
|
||||
articles = []
|
||||
|
||||
User.where.not(feed_url: [nil, ""]).find_each do |user|
|
||||
# unless forced, fetch sparingly
|
||||
next if force == false && (rand(2) == 1 || user.feed_fetched_at > 15.minutes.ago)
|
||||
|
||||
create_articles_for_user(user)
|
||||
user_articles = create_articles_for_user(user)
|
||||
articles.concat(user_articles) if user_articles
|
||||
end
|
||||
|
||||
articles
|
||||
end
|
||||
|
||||
def fetch_user(user)
|
||||
|
|
@ -28,8 +33,11 @@ class RssReader
|
|||
user.update_column(:feed_fetched_at, Time.current)
|
||||
feed = fetch_rss(user.feed_url.strip)
|
||||
|
||||
articles = []
|
||||
|
||||
feed.entries.reverse_each do |item|
|
||||
make_from_rss_item(item, user, feed)
|
||||
article = make_from_rss_item(item, user, feed)
|
||||
articles.append(article)
|
||||
rescue StandardError => e
|
||||
log_error(
|
||||
"RssReaderError: occurred while creating article",
|
||||
|
|
@ -41,6 +49,8 @@ class RssReader
|
|||
},
|
||||
)
|
||||
end
|
||||
|
||||
articles
|
||||
rescue StandardError => e
|
||||
log_error(
|
||||
"RssReaderError: occurred while fetching feed",
|
||||
|
|
@ -80,6 +90,8 @@ class RssReader
|
|||
)
|
||||
|
||||
Slack::Messengers::ArticleFetchedFeed.call(article: article)
|
||||
|
||||
article
|
||||
end
|
||||
|
||||
def get_host_without_www(url)
|
||||
|
|
|
|||
72
app/services/twitter_client/client.rb
Normal file
72
app/services/twitter_client/client.rb
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
module TwitterClient
|
||||
# Twitter client (users twitter gem as a backend)
|
||||
class Client
|
||||
class << self
|
||||
# adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
|
||||
def method_missing(method, *args, &block)
|
||||
return super unless target.respond_to?(method, false)
|
||||
|
||||
request do
|
||||
target.public_send(method, *args, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
|
||||
def respond_to_missing?(method, _include_all = false)
|
||||
target.respond_to?(method, false) || super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request
|
||||
Honeycomb.add_field("name", "twitter.client")
|
||||
yield
|
||||
rescue Twitter::Error => e
|
||||
record_error(e)
|
||||
handle_error(e)
|
||||
end
|
||||
|
||||
def record_error(exception)
|
||||
class_name = exception.class.name.demodulize
|
||||
|
||||
Honeycomb.add_field("twitter.result", "error")
|
||||
Honeycomb.add_field("twitter.error", class_name)
|
||||
DatadogStatsClient.increment(
|
||||
"twitter.errors",
|
||||
tags: ["error:#{class_name}", "message:#{exception.message}"],
|
||||
)
|
||||
end
|
||||
|
||||
def handle_error(exception)
|
||||
class_name = exception.class.name.demodulize
|
||||
|
||||
# raise specific error if known, generic one if unknown
|
||||
error_class = "::TwitterClient::Errors::#{class_name}".safe_constantize
|
||||
raise error_class, exception.message if error_class
|
||||
|
||||
error_class = if exception.class < Twitter::Error::ClientError
|
||||
TwitterClient::Errors::ClientError
|
||||
elsif exception.class < Twitter::Error::ServerError
|
||||
TwitterClient::Errors::ServerError
|
||||
else
|
||||
TwitterClient::Errors::Error
|
||||
end
|
||||
|
||||
raise error_class, exception.message
|
||||
end
|
||||
|
||||
def target
|
||||
Twitter::REST::Client.new(
|
||||
consumer_key: ApplicationConfig["TWITTER_KEY"],
|
||||
consumer_secret: ApplicationConfig["TWITTER_SECRET"],
|
||||
user_agent: "TwitterRubyGem/#{Twitter::Version} (#{URL.url})",
|
||||
timeouts: {
|
||||
connect: 5,
|
||||
read: 5,
|
||||
write: 5
|
||||
},
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/services/twitter_client/errors.rb
Normal file
15
app/services/twitter_client/errors.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
module TwitterClient
|
||||
module Errors
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
class ClientError < Error
|
||||
end
|
||||
|
||||
class ServerError < Error
|
||||
end
|
||||
|
||||
class NotFound < ClientError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -389,7 +389,7 @@ Rails.application.routes.draw do
|
|||
get "/rails/mailers/*path" => "rails/mailers#preview"
|
||||
end
|
||||
|
||||
get "/embed/:embeddable" => "liquid_embeds#show"
|
||||
get "/embed/:embeddable", to: "liquid_embeds#show", as: "liquid_embed"
|
||||
|
||||
# serviceworkers
|
||||
get "/serviceworker" => "service_worker#index"
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ FactoryBot.define do
|
|||
---
|
||||
|
||||
#{Faker::Hipster.paragraph(sentence_count: 2)}
|
||||
#{'{% tweet 1018911886862057472%}' if with_tweet_tag}
|
||||
#{'{% tweet 1018911886862057472 %}' if with_tweet_tag}
|
||||
#{Faker::Hipster.paragraph(sentence_count: 1)}
|
||||
#{"\n\n---\n\n something \n\n---\n funky in the code? \n---\n That's nice" if with_hr_issue}
|
||||
HEREDOC
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1
|
||||
10
|
||||
|
|
@ -0,0 +1 @@
|
|||
21
|
||||
|
|
@ -1 +0,0 @@
|
|||
12
|
||||
|
|
@ -21,5 +21,11 @@ Github gist here
|
|||
code block
|
||||
|
||||
```
|
||||
testsetsetsetsetsetset
|
||||
```
|
||||
testsetsetsetsetsetset lets introduce some {{ chaos }}
|
||||
|
||||
Here's more {{ what }}
|
||||
```
|
||||
|
||||
some more code and `{{ VARIABLE }}` and **_`{{ HTML }}`_**
|
||||
|
||||
### `{{ how about this }}`
|
||||
|
|
@ -3,7 +3,7 @@ require "rails_helper"
|
|||
RSpec.describe TweetTag, type: :liquid_tag do
|
||||
let(:twitter_id) { "1018911886862057472" }
|
||||
let(:handle) { "thepracticaldev" }
|
||||
let(:name) { "The Practical Dev" }
|
||||
let(:name) { "DEV Community 👩💻👨💻" }
|
||||
let(:body) { "When GitHub goes down" }
|
||||
|
||||
setup { Liquid::Template.register_tag("tweet", described_class) }
|
||||
|
|
@ -13,16 +13,18 @@ RSpec.describe TweetTag, type: :liquid_tag do
|
|||
end
|
||||
|
||||
it "accepts valid tweet id", :vcr do
|
||||
VCR.use_cassette("twitter_fetch_status") do
|
||||
VCR.use_cassette("twitter_client_status_extended") do
|
||||
liquid = generate_tweet_liquid_tag(twitter_id)
|
||||
expect(liquid.render).to include(handle)
|
||||
expect(liquid.render).to include(name)
|
||||
expect(liquid.render).to include(body)
|
||||
body = liquid.render
|
||||
|
||||
expect(body).to include(handle)
|
||||
expect(body).to include(name)
|
||||
expect(body).to include(body)
|
||||
end
|
||||
end
|
||||
|
||||
xit "render properly", :vcr do
|
||||
VCR.use_cassette("twitter_fetch_status") do
|
||||
VCR.use_cassette("twitter_client_status_extended") do
|
||||
Time.use_zone("Asia/Tokyo") do
|
||||
rendered = generate_tweet_liquid_tag(twitter_id).render
|
||||
Approvals.verify(rendered, name: "liquid_tweet_tag_spec", format: :html)
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ RSpec.describe Article, type: :model do
|
|||
end
|
||||
|
||||
it "is valid with valid liquid tags", :vcr do
|
||||
VCR.use_cassette("twitter_fetch_status") do
|
||||
VCR.use_cassette("twitter_client_status_extended") do
|
||||
article = build_and_validate_article(with_tweet_tag: true)
|
||||
expect(article).to be_valid
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,33 +3,138 @@ require "rails_helper"
|
|||
RSpec.describe Tweet, type: :model, vcr: true do
|
||||
let(:tweet_id) { "1018911886862057472" }
|
||||
let(:tweet_reply_id) { "1242938461784608770" }
|
||||
let(:retweet_id) { "1262395854469677058" }
|
||||
|
||||
it "fetches a tweet" do
|
||||
VCR.use_cassette("twitter_fetch_status") do
|
||||
tweet = described_class.fetch(tweet_id)
|
||||
expect(tweet).to be_a(described_class)
|
||||
end
|
||||
end
|
||||
it { is_expected.to validate_presence_of(:twitter_id_code) }
|
||||
it { is_expected.to validate_presence_of(:full_fetched_object_serialized) }
|
||||
|
||||
it "renders processed text" do
|
||||
VCR.use_cassette("twitter_fetch_status") do
|
||||
tweet = described_class.fetch(tweet_id)
|
||||
expect(tweet.processed_text).not_to be_nil
|
||||
end
|
||||
end
|
||||
describe ".find_or_fetch" do
|
||||
context "when retrieving a tweet", vcr: { cassette_name: "twitter_client_status_extended" } do
|
||||
it "saves a new tweet" do
|
||||
expect do
|
||||
described_class.find_or_fetch(tweet_id)
|
||||
end.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
describe "reply ids" do
|
||||
it "correctly saves in_reply_to_user_id_code" do
|
||||
VCR.use_cassette("twitter_fetch_reply") do
|
||||
tweet = described_class.fetch(tweet_reply_id)
|
||||
expect(tweet.in_reply_to_user_id_code).to eq("45042829")
|
||||
it "retrieves an existing tweet" do
|
||||
created_tweet = described_class.find_or_fetch(tweet_id)
|
||||
|
||||
expect do
|
||||
found_tweet = described_class.find_or_fetch(tweet_id)
|
||||
expect(found_tweet.id).to eq(created_tweet.id)
|
||||
end.not_to change(described_class, :count)
|
||||
end
|
||||
|
||||
it "saves the proper status ID and text" do
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
|
||||
status = tweet.full_fetched_object_serialized
|
||||
|
||||
expect(tweet.text).to eq(status[:full_text])
|
||||
expect(tweet.twitter_id_code).to eq(status[:id_str])
|
||||
end
|
||||
|
||||
it "saves the proper metadata attributes", :aggregate_failures do
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
|
||||
status = tweet.full_fetched_object_serialized
|
||||
|
||||
expect(tweet.favorite_count).to eq(status[:favorite_count])
|
||||
expect(tweet.in_reply_to_status_id_code).to be_empty
|
||||
expect(tweet.in_reply_to_user_id_code).to be_empty
|
||||
expect(tweet.in_reply_to_username).to be_empty
|
||||
expect(tweet.is_quote_status).to be(false)
|
||||
expect(tweet.quoted_tweet_id_code).to eq(status[:quoted_status_id_str])
|
||||
expect(tweet.retweet_count).to eq(status[:retweet_count])
|
||||
expect(tweet.source).to eq(status[:source])
|
||||
expect(tweet.tweeted_at.to_i).to eq(Time.zone.parse(status[:created_at]).to_i)
|
||||
end
|
||||
|
||||
it "saves the proper serializable attributes", :aggregate_failures do
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
|
||||
status = tweet.full_fetched_object_serialized
|
||||
expect(status).to be_present
|
||||
|
||||
expect(tweet.extended_entities_serialized).to eq(status[:extended_entities])
|
||||
expect(tweet.hashtags_serialized).to eq(status[:entities][:hashtags])
|
||||
expect(tweet.media_serialized).to eq(status[:entities][:media])
|
||||
expect(tweet.mentioned_usernames_serialized).to be_empty
|
||||
expect(tweet.urls_serialized).to eq(status[:entities][:urls])
|
||||
end
|
||||
|
||||
it "saves the proper user attributes", :aggregate_failures do
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
|
||||
status = tweet.full_fetched_object_serialized
|
||||
status_user = status[:user]
|
||||
|
||||
expect(tweet.remote_profile_image_url.to_s).to eq(status_user[:profile_image_url])
|
||||
expect(tweet.twitter_name).to eq(status_user[:name])
|
||||
expect(tweet.twitter_uid).to eq(status_user[:id_str])
|
||||
expect(tweet.twitter_user_followers_count).to eq(status_user[:followers_count])
|
||||
expect(tweet.twitter_user_following_count).to eq(status_user[:friends_count])
|
||||
expect(tweet.twitter_username).to eq(status_user[:screen_name].downcase)
|
||||
expect(tweet.user_is_verified).to be(status_user[:verified])
|
||||
end
|
||||
|
||||
it "sets #last_fetched_at" do
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
expect(tweet.last_fetched_at).to be_present
|
||||
end
|
||||
|
||||
it "is assignes to the existing user if the screen name corresponds" do
|
||||
user = create(:user, twitter_username: "ThePracticalDev")
|
||||
|
||||
tweet = described_class.find_or_fetch(tweet_id)
|
||||
expect(tweet.user_id).to eq(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
it "correctly saves in_reply_to_status_id_code" do
|
||||
VCR.use_cassette("twitter_fetch_reply") do
|
||||
tweet = described_class.fetch(tweet_reply_id)
|
||||
expect(tweet.in_reply_to_status_id_code).to eq("1242837746315669505")
|
||||
context "when retrieving a non existent tweet", vcr: { cassette_name: "twitter_client_status_not_found_extended" } do
|
||||
it "raises an error if the tweet does not exist" do
|
||||
expect { described_class.find_or_fetch("0") }.to raise_error(TwitterClient::Errors::NotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context "when retrieving a reply tweet", vcr: { cassette_name: "twitter_client_status_reply_extended" } do
|
||||
it "saves a new tweet" do
|
||||
expect do
|
||||
described_class.find_or_fetch(tweet_reply_id)
|
||||
end.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
it "retrieves an existing tweet" do
|
||||
created_tweet = described_class.find_or_fetch(tweet_reply_id)
|
||||
|
||||
expect do
|
||||
found_tweet = described_class.find_or_fetch(tweet_reply_id)
|
||||
expect(found_tweet.id).to eq(created_tweet.id)
|
||||
end.not_to change(described_class, :count)
|
||||
end
|
||||
|
||||
it "saves the proper reply fields" do
|
||||
tweet = described_class.find_or_fetch(tweet_reply_id)
|
||||
|
||||
status = tweet.full_fetched_object_serialized
|
||||
|
||||
expect(tweet.in_reply_to_status_id_code).to eq(status[:in_reply_to_status_id_str])
|
||||
expect(tweet.in_reply_to_user_id_code).to eq(status[:in_reply_to_user_id_str])
|
||||
expect(tweet.in_reply_to_username).to eq(status[:in_reply_to_screen_name])
|
||||
end
|
||||
end
|
||||
|
||||
context "when retrieving a reply tweet", vcr: { cassette_name: "twitter_client_status_retweet_extended" } do
|
||||
it "saves a new tweet" do
|
||||
expect do
|
||||
described_class.find_or_fetch(retweet_id)
|
||||
end.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
it "saves the proper status ID" do
|
||||
tweet = described_class.find_or_fetch(retweet_id)
|
||||
|
||||
expect(tweet.twitter_id_code).not_to eq(retweet_id) # we fetch the original tweet
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,25 +1,27 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe "LiquidEmbeds", type: :request, vcr: VCR_OPTIONS[:twitter_fetch_status] do
|
||||
RSpec.describe "LiquidEmbeds", type: :request, vcr: { cassette_name: "twitter_client_status_extended" } do
|
||||
describe "get /embeds" do
|
||||
let(:path) { liquid_embed_path("tweet", args: 1_018_911_886_862_057_472) }
|
||||
|
||||
it "renders proper tweet" do
|
||||
get "/embed/tweet?args=1018911886862057472"
|
||||
get path
|
||||
expect(response.body).to include("ltag__twitter-tweet")
|
||||
end
|
||||
|
||||
it "renders proper css" do
|
||||
get "/embed/tweet?args=1018911886862057472"
|
||||
it "renders proper CSS" do
|
||||
get path
|
||||
expect(response.body).to include("blockquote.ltag__twitter-tweet")
|
||||
end
|
||||
|
||||
it "renders 404 if improper tweet" do
|
||||
expect do
|
||||
get "/embed/tweet?args=improper"
|
||||
get liquid_embed_path("tweet", args: "improper")
|
||||
end.to raise_error(ActionView::Template::Error)
|
||||
end
|
||||
|
||||
it "contains base target parent" do
|
||||
get "/embed/tweet?args=1018911886862057472"
|
||||
get path
|
||||
expect(response.body).to include('<base target="_parent">')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ require "rss"
|
|||
|
||||
default_logger = Rails.logger
|
||||
|
||||
RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
||||
RSpec.describe RssReader, type: :service, vcr: true do
|
||||
let(:link) { "https://medium.com/feed/@vaidehijoshi" }
|
||||
let(:nonmedium_link) { "https://circleci.com/blog/feed.xml" }
|
||||
let(:nonpermanent_link) { "https://medium.com/feed/@macsiri/" }
|
||||
|
|
@ -25,21 +25,21 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
end
|
||||
|
||||
it "fetch only articles from an feed_url" do
|
||||
rss_reader.get_all_articles
|
||||
it "fetch only articles from a feed_url", vcr: { cassette_name: "rss_reader_fetch_articles" } do
|
||||
articles = rss_reader.get_all_articles
|
||||
|
||||
# the result within the approval file depends on the feed
|
||||
# not fetching comments is baked into this
|
||||
verify(format: :txt) { Article.count }
|
||||
verify(format: :txt) { articles.length }
|
||||
end
|
||||
|
||||
it "does not re-create article if it already exist" do
|
||||
it "does not recreate articles if they already exist", vcr: { cassette_name: "rss_reader_fetch_articles_twice" } do
|
||||
rss_reader.get_all_articles
|
||||
|
||||
expect { rss_reader.get_all_articles }.not_to change(Article, :count)
|
||||
end
|
||||
|
||||
it "parses correctly" do
|
||||
it "parses correctly", vcr: { cassette_name: "rss_reader_fetch_articles" } do
|
||||
rss_reader.get_all_articles
|
||||
|
||||
verify format: :txt do
|
||||
|
|
@ -47,7 +47,7 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
end
|
||||
|
||||
it "sets feed_fetched_at to the current time" do
|
||||
it "sets feed_fetched_at to the current time", vcr: { cassette_name: "rss_reader_fetch_articles" } do
|
||||
Timecop.freeze(Time.current) do
|
||||
rss_reader.get_all_articles
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
end
|
||||
|
||||
it "does refetch same user over and over by default" do
|
||||
it "does refetch same user over and over by default", vcr: { cassette_name: "rss_reader_fetch_multiple_times" } do
|
||||
user = User.find_by(feed_url: nonpermanent_link)
|
||||
|
||||
Timecop.freeze(Time.current) do
|
||||
|
|
@ -94,10 +94,10 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
expect(Rails.logger).to have_received(:error).at_least(:once)
|
||||
end
|
||||
|
||||
it "queues as many slack messages as there are articles" do
|
||||
expect do
|
||||
rss_reader.get_all_articles
|
||||
end.to change(Slack::Messengers::Worker.jobs, :count).by(12)
|
||||
it "queues as many slack messages as there are articles", vcr: { cassette_name: "rss_reader_fetch_articles" } do
|
||||
old_count = Slack::Messengers::Worker.jobs.count
|
||||
articles = rss_reader.get_all_articles
|
||||
expect(Slack::Messengers::Worker.jobs.count).to eq(old_count + articles.length)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#fetch_user" do
|
||||
describe "#fetch_user", vcr: { cassette_name: "rss_reader_fetch_medium_feed" } do
|
||||
before do
|
||||
[link, nonmedium_link, nonpermanent_link].each do |feed_url|
|
||||
create(:user, feed_url: feed_url)
|
||||
|
|
@ -123,10 +123,10 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
|
||||
it "gets articles for user" do
|
||||
rss_reader.fetch_user(User.find_by(feed_url: link))
|
||||
articles = rss_reader.fetch_user(User.find_by(feed_url: link))
|
||||
|
||||
# the result within the approval file depends on the feed
|
||||
verify(format: :txt) { Article.count }
|
||||
verify(format: :txt) { articles.length }
|
||||
end
|
||||
|
||||
it "does not set featured_number" do
|
||||
|
|
@ -155,9 +155,9 @@ RSpec.describe RssReader, type: :service, vcr: VCR_OPTIONS[:rss_feeds] do
|
|||
end
|
||||
|
||||
it "queues as many slack messages as there are user articles" do
|
||||
expect do
|
||||
rss_reader.fetch_user(User.find_by(feed_url: link))
|
||||
end.to change(Slack::Messengers::Worker.jobs, :count).by(1)
|
||||
old_count = Slack::Messengers::Worker.jobs.count
|
||||
articles = rss_reader.fetch_user(User.find_by(feed_url: link))
|
||||
expect(Slack::Messengers::Worker.jobs.count).to eq(old_count + articles.length)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
22
spec/services/twitter_client/client_spec.rb
Normal file
22
spec/services/twitter_client/client_spec.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe TwitterClient::Client, type: :service, vcr: true do
|
||||
let(:tweet_id) { "1018911886862057472" }
|
||||
|
||||
describe ".status" do
|
||||
it "returns a status" do
|
||||
VCR.use_cassette("twitter_client_status") do
|
||||
tweet = described_class.status(tweet_id)
|
||||
expect(tweet.text).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
it "raises NotFound if the status does not exist" do
|
||||
VCR.use_cassette("twitter_client_status_not_found") do
|
||||
expect do
|
||||
described_class.status(0)
|
||||
end.to raise_error(TwitterClient::Errors::NotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
145
spec/support/fixtures/vcr_cassettes/twitter_client_status.yml
Normal file
145
spec/support/fixtures/vcr_cassettes/twitter_client_status.yml
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 12:41:17 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 12:41:16 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- b808ab37862bae0eb94f753a5cd96dd5
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '107'
|
||||
X-Transaction:
|
||||
- '00494008004581f6'
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '1'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 12:41:17 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/1018911886862057472.json
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '4181'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 12:41:17 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 12:41:17 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Access-Level:
|
||||
- read
|
||||
X-Connection-Hash:
|
||||
- a3e8c4da447fc5bcef97874cbd59a994
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '896'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589805893'
|
||||
X-Response-Time:
|
||||
- '131'
|
||||
X-Transaction:
|
||||
- '0094e40000aabfb7'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"created_at":"Mon Jul 16 17:34:58 +0000 2018","id":1018911886862057472,"id_str":"1018911886862057472","text":"When
|
||||
GitHub goes down https:\/\/t.co\/5Laf1GtUSS","truncated":false,"entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[],"media":[{"id":1018911875919212546,"id_str":"1018911875919212546","indices":[22,45],"media_url":"http:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","media_url_https":"https:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","url":"https:\/\/t.co\/5Laf1GtUSS","display_url":"pic.twitter.com\/5Laf1GtUSS","expanded_url":"https:\/\/twitter.com\/ThePracticalDev\/status\/1018911886862057472\/photo\/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":400,"h":312,"resize":"fit"},"large":{"w":400,"h":312,"resize":"fit"},"small":{"w":400,"h":312,"resize":"fit"}}}]},"extended_entities":{"media":[{"id":1018911875919212546,"id_str":"1018911875919212546","indices":[22,45],"media_url":"http:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","media_url_https":"https:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","url":"https:\/\/t.co\/5Laf1GtUSS","display_url":"pic.twitter.com\/5Laf1GtUSS","expanded_url":"https:\/\/twitter.com\/ThePracticalDev\/status\/1018911886862057472\/photo\/1","type":"animated_gif","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":400,"h":312,"resize":"fit"},"large":{"w":400,"h":312,"resize":"fit"},"small":{"w":400,"h":312,"resize":"fit"}},"video_info":{"aspect_ratio":[50,39],"variants":[{"bitrate":0,"content_type":"video\/mp4","url":"https:\/\/video.twimg.com\/tweet_video\/DiPm8-WXcAI3_qS.mp4"}]}}]},"source":"\u003ca
|
||||
href=\"http:\/\/twitter.com\" rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":2735246778,"id_str":"2735246778","name":"DEV
|
||||
Community \ud83d\udc69\u200d\ud83d\udcbb\ud83d\udc68\u200d\ud83d\udcbb","screen_name":"ThePracticalDev","location":"","description":"Great
|
||||
posts from the amazing https:\/\/t.co\/xHvFQQ9jeO community, with some opinion
|
||||
and humor mixed in. Created by @bendhalpern. Join https:\/\/t.co\/xHvFQQ9jeO!","url":"https:\/\/t.co\/lhcCPP1ReQ","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/lhcCPP1ReQ","expanded_url":"http:\/\/dev.to","display_url":"dev.to","indices":[0,23]}]},"description":{"urls":[{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[29,52]},{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[132,155]}]}},"protected":false,"followers_count":191639,"friends_count":2311,"listed_count":3793,"created_at":"Fri
|
||||
Aug 15 19:11:17 +0000 2014","favourites_count":48516,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":true,"statuses_count":38686,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"131516","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":true,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/2735246778\/1557714134","profile_link_color":"14BD7B","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":true,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":82,"favorite_count":263,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 12:41:17 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -1,5 +1,74 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 12:48:44 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 12:48:44 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- 4a0eff9d35d94b917c6a394d78e0c178
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '114'
|
||||
X-Transaction:
|
||||
- 004bebdc006e667c
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '0'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 12:48:44 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/1018911886862057472.json?tweet_mode=extended
|
||||
|
|
@ -8,7 +77,7 @@ http_interactions:
|
|||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/6.2.0
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
|
|
@ -23,27 +92,27 @@ http_interactions:
|
|||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '4159'
|
||||
- '4214'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Tue, 17 Jul 2018 20:09:47 GMT
|
||||
- Mon, 18 May 2020 12:48:44 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Tue, 17 Jul 2018 20:09:47 GMT
|
||||
- Mon, 18 May 2020 12:48:44 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_b
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Access-Level:
|
||||
- read-write
|
||||
- read
|
||||
X-Connection-Hash:
|
||||
- fc498ba11baf16a5fd6822ed64fb207d
|
||||
- 50e8c947e1620a984e9ec9ab6d860012
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
|
|
@ -51,26 +120,26 @@ http_interactions:
|
|||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '893'
|
||||
- '899'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1531858493'
|
||||
- '1589807024'
|
||||
X-Response-Time:
|
||||
- '66'
|
||||
- '127'
|
||||
X-Transaction:
|
||||
- '00208a050094194c'
|
||||
- '0071193c00ff8788'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- 1; mode=block; report=https://twitter.com/i/xss_report
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"created_at":"Mon Jul 16 17:34:58 +0000 2018","id":1018911886862057472,"id_str":"1018911886862057472","full_text":"When
|
||||
GitHub goes down https:\/\/t.co\/5Laf1GtUSS","truncated":false,"display_text_range":[0,21],"entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[],"media":[{"id":1018911875919212546,"id_str":"1018911875919212546","indices":[22,45],"media_url":"http:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","media_url_https":"https:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","url":"https:\/\/t.co\/5Laf1GtUSS","display_url":"pic.twitter.com\/5Laf1GtUSS","expanded_url":"https:\/\/twitter.com\/ThePracticalDev\/status\/1018911886862057472\/photo\/1","type":"photo","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":400,"h":312,"resize":"fit"},"large":{"w":400,"h":312,"resize":"fit"},"small":{"w":400,"h":312,"resize":"fit"}}}]},"extended_entities":{"media":[{"id":1018911875919212546,"id_str":"1018911875919212546","indices":[22,45],"media_url":"http:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","media_url_https":"https:\/\/pbs.twimg.com\/tweet_video_thumb\/DiPm8-WXcAI3_qS.jpg","url":"https:\/\/t.co\/5Laf1GtUSS","display_url":"pic.twitter.com\/5Laf1GtUSS","expanded_url":"https:\/\/twitter.com\/ThePracticalDev\/status\/1018911886862057472\/photo\/1","type":"animated_gif","sizes":{"thumb":{"w":150,"h":150,"resize":"crop"},"medium":{"w":400,"h":312,"resize":"fit"},"large":{"w":400,"h":312,"resize":"fit"},"small":{"w":400,"h":312,"resize":"fit"}},"video_info":{"aspect_ratio":[50,39],"variants":[{"bitrate":0,"content_type":"video\/mp4","url":"https:\/\/video.twimg.com\/tweet_video\/DiPm8-WXcAI3_qS.mp4"}]}}]},"source":"\u003ca
|
||||
href=\"http:\/\/twitter.com\" rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":2735246778,"id_str":"2735246778","name":"The
|
||||
Practical Dev","screen_name":"ThePracticalDev","location":"","description":"Great
|
||||
href=\"http:\/\/twitter.com\" rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":2735246778,"id_str":"2735246778","name":"DEV
|
||||
Community \ud83d\udc69\u200d\ud83d\udcbb\ud83d\udc68\u200d\ud83d\udcbb","screen_name":"ThePracticalDev","location":"","description":"Great
|
||||
posts from the amazing https:\/\/t.co\/xHvFQQ9jeO community, with some opinion
|
||||
and humor mixed in. Created by @bendhalpern. Join https:\/\/t.co\/xHvFQQ9jeO!","url":"https:\/\/t.co\/lhcCPP1ReQ","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/lhcCPP1ReQ","expanded_url":"http:\/\/dev.to","display_url":"dev.to","indices":[0,23]}]},"description":{"urls":[{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[29,52]},{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[132,155]}]}},"protected":false,"followers_count":147060,"friends_count":2258,"listed_count":3145,"created_at":"Fri
|
||||
Aug 15 19:11:17 +0000 2014","favourites_count":42288,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":false,"statuses_count":18387,"lang":"en","contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"131516","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":true,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1002604104194056192\/IEoNsLNM_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1002604104194056192\/IEoNsLNM_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/2735246778\/1492833420","profile_link_color":"14BD7B","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":true,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":true,"follow_request_sent":false,"notifications":false,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":91,"favorite_count":276,"favorited":true,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"}'
|
||||
http_version:
|
||||
recorded_at: Tue, 17 Jul 2018 20:09:47 GMT
|
||||
recorded_with: VCR 4.0.0
|
||||
and humor mixed in. Created by @bendhalpern. Join https:\/\/t.co\/xHvFQQ9jeO!","url":"https:\/\/t.co\/lhcCPP1ReQ","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/lhcCPP1ReQ","expanded_url":"http:\/\/dev.to","display_url":"dev.to","indices":[0,23]}]},"description":{"urls":[{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[29,52]},{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[132,155]}]}},"protected":false,"followers_count":191641,"friends_count":2311,"listed_count":3793,"created_at":"Fri
|
||||
Aug 15 19:11:17 +0000 2014","favourites_count":48516,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":true,"statuses_count":38686,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"131516","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":true,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/2735246778\/1557714134","profile_link_color":"14BD7B","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":true,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":82,"favorite_count":263,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 12:48:44 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 16:09:44 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 16:09:44 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- c6b4eb440837c9010b219c99effa8141
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '116'
|
||||
X-Transaction:
|
||||
- 00a3fa16001000f5
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '1'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 16:09:44 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/0.json
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 404
|
||||
message: Not Found
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '71'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 16:09:44 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 16:09:44 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 404 Not Found
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- a16f087a18e4315ecbc158f3e8947aa7
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '899'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589819084'
|
||||
X-Response-Time:
|
||||
- '114'
|
||||
X-Transaction:
|
||||
- 0035566e00d64ce7
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"errors":[{"code":8,"message":"No data available for specified ID."}]}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 16:09:44 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:46:21 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:46:21 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- c745e01b2e126fa33f799e05ae0c848b
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '116'
|
||||
X-Transaction:
|
||||
- 00d4dfbe006f4d83
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '0'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:46:21 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/0.json?tweet_mode=extended
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 404
|
||||
message: Not Found
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '71'
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:46:21 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:46:21 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 404 Not Found
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- aa96b1523d91f21bc57cc858a291326c
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '898'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589814001'
|
||||
X-Response-Time:
|
||||
- '116'
|
||||
X-Transaction:
|
||||
- 00d8302700668f57
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"errors":[{"code":8,"message":"No data available for specified ID."}]}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:46:21 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:25:50 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:25:50 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- 3ac1eba3289eeef0ab2b6cc87580e474
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '110'
|
||||
X-Transaction:
|
||||
- 003aeaa5005d5e26
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '0'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:25:50 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/1242938461784608770.json?tweet_mode=extended
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '2533'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:25:51 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:25:51 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Access-Level:
|
||||
- read
|
||||
X-Connection-Hash:
|
||||
- 988e2ce230c1c018731301f04e0f8b73
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '899'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589812851'
|
||||
X-Response-Time:
|
||||
- '134'
|
||||
X-Transaction:
|
||||
- 001c06cc00a36c5e
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"created_at":"Wed Mar 25 22:16:36 +0000 2020","id":1242938461784608770,"id_str":"1242938461784608770","full_text":"@MattDomm_
|
||||
Yes! :D","truncated":false,"display_text_range":[11,18],"entities":{"hashtags":[],"symbols":[],"user_mentions":[{"screen_name":"MattDomm_","name":"Matt
|
||||
Domm","id":45042829,"id_str":"45042829","indices":[0,10]}],"urls":[]},"source":"\u003ca
|
||||
href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e","in_reply_to_status_id":1242837746315669505,"in_reply_to_status_id_str":"1242837746315669505","in_reply_to_user_id":45042829,"in_reply_to_user_id_str":"45042829","in_reply_to_screen_name":"MattDomm_","user":{"id":1105243879589195777,"id_str":"1105243879589195777","name":"Codeland","screen_name":"codelandconf","location":"NYC","description":"Produced
|
||||
by @ThePracticalDev @CodeNewbies. The conference for new and growing developers.","url":"https:\/\/t.co\/Yu6ibinH6I","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/Yu6ibinH6I","expanded_url":"https:\/\/codelandconf.com","display_url":"codelandconf.com","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":2414,"friends_count":15,"listed_count":33,"created_at":"Mon
|
||||
Mar 11 23:07:30 +0000 2019","favourites_count":2851,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":false,"statuses_count":2542,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"000000","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1233079056150736896\/qkSuQpiX_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1233079056150736896\/qkSuQpiX_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/1105243879589195777\/1585092823","profile_link_color":"FF01FF","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":false,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":0,"favorite_count":0,"favorited":false,"retweeted":false,"lang":"en"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:25:51 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:59:16 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:59:16 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- 0ed066348bd2a09f1a4ab67364222291
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '124'
|
||||
X-Transaction:
|
||||
- 00bc6963002453ac
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '0'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:59:16 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/1262395854469677058.json?tweet_mode=extended
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '5843'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:59:16 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:59:16 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Access-Level:
|
||||
- read
|
||||
X-Connection-Hash:
|
||||
- f049dc981bb59177959f2e672d20ab06
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '896'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589814001'
|
||||
X-Response-Time:
|
||||
- '142'
|
||||
X-Transaction:
|
||||
- '009e83bf00c3d0db'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"created_at":"Mon May 18 14:53:20 +0000 2020","id":1262395854469677058,"id_str":"1262395854469677058","full_text":"RT
|
||||
@ThePracticalDev: \"The goal of this guide is to provide enough knowledge
|
||||
to be conversational, as well as to give a strong jumping off p\u2026","truncated":false,"display_text_range":[0,140],"entities":{"hashtags":[],"symbols":[],"user_mentions":[{"screen_name":"ThePracticalDev","name":"DEV
|
||||
Community \ud83d\udc69\u200d\ud83d\udcbb\ud83d\udc68\u200d\ud83d\udcbb","id":2735246778,"id_str":"2735246778","indices":[3,19]}],"urls":[]},"source":"\u003ca
|
||||
href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter
|
||||
for iPhone\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":815325836,"id_str":"815325836","name":"Great","screen_name":"01Blows","location":"","description":"","url":null,"entities":{"description":{"urls":[]}},"protected":false,"followers_count":28,"friends_count":106,"listed_count":14,"created_at":"Mon
|
||||
Sep 10 14:20:14 +0000 2012","favourites_count":62,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":false,"statuses_count":2686,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"C0DEED","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/2970316093\/4b4015e8e6fe419e375d1e22d3349889_normal.jpeg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/2970316093\/4b4015e8e6fe419e375d1e22d3349889_normal.jpeg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/815325836\/1355402666","profile_link_color":"1DA1F2","profile_sidebar_border_color":"C0DEED","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"has_extended_profile":false,"default_profile":true,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"retweeted_status":{"created_at":"Mon
|
||||
May 18 14:32:00 +0000 2020","id":1262390485399805953,"id_str":"1262390485399805953","full_text":"\"The
|
||||
goal of this guide is to provide enough knowledge to be conversational, as
|
||||
well as to give a strong jumping off point if you were to start learning TypeScript
|
||||
on the job.\"\n\n\u007b author: @shane__lonergan \u007d #DEVCommunity https:\/\/t.co\/K5V4s91cJy","truncated":false,"display_text_range":[0,244],"entities":{"hashtags":[{"text":"DEVCommunity","indices":[207,220]}],"symbols":[],"user_mentions":[{"screen_name":"shane__lonergan","name":"Shane
|
||||
Lonergan \ud83c\udfa4\u2328\ufe0f","id":1164944561304690688,"id_str":"1164944561304690688","indices":[188,204]}],"urls":[{"url":"https:\/\/t.co\/K5V4s91cJy","expanded_url":"https:\/\/dev.to\/shane__lonergan\/typescript-in-a-weekend-a-crash-course-2171","display_url":"dev.to\/shane__lonerga\u2026","indices":[221,244]}]},"source":"\u003ca
|
||||
href=\"https:\/\/buffer.com\" rel=\"nofollow\"\u003eBuffer\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":2735246778,"id_str":"2735246778","name":"DEV
|
||||
Community \ud83d\udc69\u200d\ud83d\udcbb\ud83d\udc68\u200d\ud83d\udcbb","screen_name":"ThePracticalDev","location":"","description":"Great
|
||||
posts from the amazing https:\/\/t.co\/xHvFQQ9jeO community, with some opinion
|
||||
and humor mixed in. Created by @bendhalpern. Join https:\/\/t.co\/xHvFQQ9jeO!","url":"https:\/\/t.co\/lhcCPP1ReQ","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/lhcCPP1ReQ","expanded_url":"http:\/\/dev.to","display_url":"dev.to","indices":[0,23]}]},"description":{"urls":[{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[29,52]},{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[132,155]}]}},"protected":false,"followers_count":191666,"friends_count":2311,"listed_count":3793,"created_at":"Fri
|
||||
Aug 15 19:11:17 +0000 2014","favourites_count":48516,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":true,"statuses_count":38690,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"131516","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":true,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/2735246778\/1557714134","profile_link_color":"14BD7B","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":true,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":9,"favorite_count":19,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"},"is_quote_status":false,"retweet_count":9,"favorite_count":0,"favorited":false,"retweeted":false,"lang":"en"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:59:16 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.twitter.com/oauth2/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: grant_type=client_credentials
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Accept:
|
||||
- "*/*"
|
||||
Connection:
|
||||
- close
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '153'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:59:17 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:59:17 GMT
|
||||
Ml:
|
||||
- A
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Connection-Hash:
|
||||
- eeef3e85c1fa03a5d4e20d85d95cc05e
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- DENY
|
||||
X-Response-Time:
|
||||
- '115'
|
||||
X-Transaction:
|
||||
- 00d5cdaa005fc247
|
||||
X-Tsa-Request-Body-Time:
|
||||
- '1'
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Ua-Compatible:
|
||||
- IE=edge,chrome=1
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:59:17 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.twitter.com/1.1/statuses/show/1262390485399805953.json
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- TwitterRubyGem/7.0.0 (http://localhost:3000)
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Cache-Control:
|
||||
- no-cache, no-store, must-revalidate, pre-check=0, post-check=0
|
||||
Connection:
|
||||
- close
|
||||
Content-Disposition:
|
||||
- attachment; filename=json.json
|
||||
Content-Length:
|
||||
- '3038'
|
||||
Content-Type:
|
||||
- application/json;charset=utf-8
|
||||
Date:
|
||||
- Mon, 18 May 2020 14:59:17 GMT
|
||||
Expires:
|
||||
- Tue, 31 Mar 1981 05:00:00 GMT
|
||||
Last-Modified:
|
||||
- Mon, 18 May 2020 14:59:17 GMT
|
||||
Pragma:
|
||||
- no-cache
|
||||
Server:
|
||||
- tsa_o
|
||||
Status:
|
||||
- 200 OK
|
||||
Strict-Transport-Security:
|
||||
- max-age=631138519
|
||||
X-Access-Level:
|
||||
- read
|
||||
X-Connection-Hash:
|
||||
- fd489dd89ded9e04dc9df080d7cbc52d
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Rate-Limit-Limit:
|
||||
- '900'
|
||||
X-Rate-Limit-Remaining:
|
||||
- '895'
|
||||
X-Rate-Limit-Reset:
|
||||
- '1589814001'
|
||||
X-Response-Time:
|
||||
- '130'
|
||||
X-Transaction:
|
||||
- 00dc05fb002b905b
|
||||
X-Twitter-Response-Tags:
|
||||
- BouncerCompliant
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"created_at":"Mon May 18 14:32:00 +0000 2020","id":1262390485399805953,"id_str":"1262390485399805953","text":"\"The
|
||||
goal of this guide is to provide enough knowledge to be conversational, as
|
||||
well as to give a strong jumping of\u2026 https:\/\/t.co\/firzrhsCY8","truncated":true,"entities":{"hashtags":[],"symbols":[],"user_mentions":[],"urls":[{"url":"https:\/\/t.co\/firzrhsCY8","expanded_url":"https:\/\/twitter.com\/i\/web\/status\/1262390485399805953","display_url":"twitter.com\/i\/web\/status\/1\u2026","indices":[117,140]}]},"source":"\u003ca
|
||||
href=\"https:\/\/buffer.com\" rel=\"nofollow\"\u003eBuffer\u003c\/a\u003e","in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"user":{"id":2735246778,"id_str":"2735246778","name":"DEV
|
||||
Community \ud83d\udc69\u200d\ud83d\udcbb\ud83d\udc68\u200d\ud83d\udcbb","screen_name":"ThePracticalDev","location":"","description":"Great
|
||||
posts from the amazing https:\/\/t.co\/xHvFQQ9jeO community, with some opinion
|
||||
and humor mixed in. Created by @bendhalpern. Join https:\/\/t.co\/xHvFQQ9jeO!","url":"https:\/\/t.co\/lhcCPP1ReQ","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/lhcCPP1ReQ","expanded_url":"http:\/\/dev.to","display_url":"dev.to","indices":[0,23]}]},"description":{"urls":[{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[29,52]},{"url":"https:\/\/t.co\/xHvFQQ9jeO","expanded_url":"https:\/\/dev.to","display_url":"dev.to","indices":[132,155]}]}},"protected":false,"followers_count":191666,"friends_count":2311,"listed_count":3793,"created_at":"Fri
|
||||
Aug 15 19:11:17 +0000 2014","favourites_count":48516,"utc_offset":null,"time_zone":null,"geo_enabled":false,"verified":true,"statuses_count":38690,"lang":null,"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"131516","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png","profile_background_tile":true,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1253165670935773185\/SkSoEQL3_normal.jpg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/2735246778\/1557714134","profile_link_color":"14BD7B","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"000000","profile_text_color":"000000","profile_use_background_image":true,"has_extended_profile":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null,"translator_type":"none"},"geo":null,"coordinates":null,"place":null,"contributors":null,"is_quote_status":false,"retweet_count":9,"favorite_count":19,"favorited":false,"retweeted":false,"possibly_sensitive":false,"possibly_sensitive_appealable":false,"lang":"en"}'
|
||||
http_version: null
|
||||
recorded_at: Mon, 18 May 2020 14:59:17 GMT
|
||||
recorded_with: VCR 5.1.0
|
||||
|
|
@ -17,6 +17,13 @@ VCR.configure do |config|
|
|||
|
||||
# Removes all private data (Basic Auth, Set-Cookie headers...)
|
||||
config.before_record do |i|
|
||||
# Twitter embeds the Bearer access token in the JSON HTTP response
|
||||
if i.request.uri.include?("api.twitter.com/oauth2/token")
|
||||
data = JSON.parse(i.response.body)
|
||||
data["access_token"] = "ACCESS_TOKEN"
|
||||
i.response.body = data.to_json
|
||||
end
|
||||
|
||||
i.response.headers.delete("Set-Cookie")
|
||||
i.request.headers.delete("Authorization")
|
||||
|
||||
|
|
@ -24,14 +31,3 @@ VCR.configure do |config|
|
|||
i.request.uri.sub!(/:\/\/.*#{Regexp.escape(u.host)}/, "://#{u.host}")
|
||||
end
|
||||
end
|
||||
|
||||
VCR_OPTIONS = {
|
||||
twitter_fetch_status: {
|
||||
cassette_name: "twitter_fetch_status",
|
||||
allow_playback_repeats: true
|
||||
},
|
||||
rss_feeds: {
|
||||
cassette_name: "rss_feeds",
|
||||
allow_playback_repeats: true
|
||||
}
|
||||
}.freeze
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue