Merge pull request #227 from Retrospring/fix/tweet-length

Fixes to ensure answers shared to twitter post more reliably
This commit is contained in:
Karina Kwiatek 2021-12-25 22:39:56 +01:00 committed by GitHub
commit c773d43447
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 18 deletions

View File

@ -12,9 +12,10 @@ RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get update -qq \ RUN apt-get update -qq \
&& apt-get install -y --no-install-recommends build-essential \ && apt-get install -y --no-install-recommends build-essential \
libpq-dev postgresql-client \ libpq-dev postgresql-client \
libxml2-dev libxslt1-dev \ libxml2-dev libxslt1-dev \
libmagickwand-dev imagemagick \ libmagickwand-dev imagemagick \
libidn11-dev \
nodejs \ nodejs \
yarn \ yarn \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*

View File

@ -52,7 +52,7 @@ jobs:
with: with:
node-version: '12' node-version: '12'
- name: Install dependencies - name: Install dependencies
run: sudo apt update && sudo apt-get install -y libpq-dev libxml2-dev libxslt1-dev libmagickwand-dev imagemagick run: sudo apt update && sudo apt-get install -y libpq-dev libxml2-dev libxslt1-dev libmagickwand-dev imagemagick libidn11-dev
- name: Copy default configuration - name: Copy default configuration
run: | run: |
cp config/database.yml.postgres config/database.yml cp config/database.yml.postgres config/database.yml

View File

@ -57,6 +57,7 @@ gem 'omniauth-tumblr'
# OAuth clients # OAuth clients
gem 'twitter' gem 'twitter'
gem 'twitter-text'
# To use a more recent Faraday version, a fork of this gem is required. # To use a more recent Faraday version, a fork of this gem is required.
gem 'tumblr_client', git: 'https://github.com/amplifr/tumblr_client' gem 'tumblr_client', git: 'https://github.com/amplifr/tumblr_client'

View File

@ -251,6 +251,7 @@ GEM
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n-js (3.6.0) i18n-js (3.6.0)
i18n (>= 0.6.6) i18n (>= 0.6.6)
idn-ruby (0.1.4)
image_processing (1.12.1) image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
@ -534,6 +535,9 @@ GEM
multipart-post (~> 2.0) multipart-post (~> 2.0)
naught (~> 1.0) naught (~> 1.0)
simple_oauth (~> 0.3.0) simple_oauth (~> 0.3.0)
twitter-text (3.1.0)
idn-ruby
unf (~> 0.1.0)
tzinfo (1.2.9) tzinfo (1.2.9)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (4.2.0) uglifier (4.2.0)
@ -632,6 +636,7 @@ DEPENDENCIES
tumblr_client! tumblr_client!
turbolinks (~> 2.5.3) turbolinks (~> 2.5.3)
twitter twitter
twitter-text
uglifier (>= 1.3.0) uglifier (>= 1.3.0)
web-console (< 4.0.0) web-console (< 4.0.0)
webpacker (~> 5.2) webpacker (~> 5.2)

View File

@ -48,7 +48,9 @@ class Ajax::AnswerController < AjaxController
end end
services = JSON.parse params[:share] services = JSON.parse params[:share]
ShareWorker.perform_async(current_user.id, answer.id, services) services.each do |service|
ShareWorker.perform_async(current_user.id, answer.id, service)
end
@response[:status] = :okay @response[:status] = :okay

View File

@ -27,16 +27,30 @@ class Services::Twitter < Service
end end
def prepare_tweet(answer) def prepare_tweet(answer)
# TODO: improve this.
question_content = twitter_markdown answer.question.content.gsub(/\@(\w+)/, '\1') question_content = twitter_markdown answer.question.content.gsub(/\@(\w+)/, '\1')
original_question_length = question_content.length
answer_content = twitter_markdown answer.content answer_content = twitter_markdown answer.content
original_answer_length = answer_content.length
answer_url = show_user_answer_url( answer_url = show_user_answer_url(
id: answer.id, id: answer.id,
username: answer.user.screen_name, username: answer.user.screen_name,
host: APP_CONFIG['hostname'], host: APP_CONFIG['hostname'],
protocol: (APP_CONFIG['https'] ? :https : :http) protocol: (APP_CONFIG['https'] ? :https : :http)
) )
"#{question_content[0..122]}#{'…' if question_content.length > 123}" \
"#{answer_content[0..123]}#{'…' if answer_content.length > 124} #{answer_url}" parsed_tweet = { :valid => false }
tweet_text = ""
until parsed_tweet[:valid]
tweet_text = "#{question_content[0..122]}#{'…' if original_question_length > [123, question_content.length].min}" \
"#{answer_content[0..123]}#{'…' if original_answer_length > [124, answer_content.length].min} #{answer_url}"
parsed_tweet = Twitter::TwitterText::Validation::parse_tweet(tweet_text)
question_content = question_content[0..-2]
answer_content = answer_content[0..-2]
end
tweet_text
end end
end end

View File

@ -1,19 +1,19 @@
class ShareWorker class ShareWorker
include Sidekiq::Worker include Sidekiq::Worker
sidekiq_options queue: :share, retry: false sidekiq_options queue: :share, retry: 5
# @param user_id [Integer] the user id # @param user_id [Integer] the user id
# @param answer_id [Integer] the user id # @param answer_id [Integer] the user id
# @param services [Array] array containing strings # @param service [String] the service to post to
def perform(user_id, answer_id, services) def perform(user_id, answer_id, service)
User.find(user_id).services.each do |service| service_type = "Services::#{service.camelize}"
begin user_service = User.find(user_id).services.find_by(type: service_type)
service.post(Answer.find(answer_id)) if services.include? service.provider
rescue => e user_service.post(Answer.find(answer_id))
logger.info "failed to post answer #{answer_id} to #{service.provider} for user #{user_id}: #{e.message}" rescue => e
NewRelic::Agent.notice_error(e) logger.info "failed to post answer #{answer_id} to #{service.provider} for user #{user_id}: #{e.message}"
end NewRelic::Agent.notice_error(e)
end raise
end end
end end

View File

@ -27,7 +27,9 @@ describe Ajax::AnswerController, :ajax_controller, type: :controller do
it "enqueues a job for sharing the answer to social networks" do it "enqueues a job for sharing the answer to social networks" do
subject subject
expect(ShareWorker).to have_enqueued_sidekiq_job(user.id, Answer.last.id, shared_services) shared_services.each do |service|
expect(ShareWorker).to have_enqueued_sidekiq_job(user.id, Answer.last.id, service)
end
end end
include_examples "returns the expected response" include_examples "returns the expected response"

View File

@ -0,0 +1,46 @@
# frozen_string_literal: true
require 'rails_helper'
describe Services::Twitter do
describe "#post" do
let(:user) { FactoryBot.create(:user) }
let(:service) { Services::Twitter.create(user: user) }
let(:answer) { FactoryBot.create(:answer, user: user,
content: 'a' * 255,
question_content: 'q' * 255) }
let(:twitter_client) { instance_double(Twitter::REST::Client) }
before do
allow(Twitter::REST::Client).to receive(:new).and_return(twitter_client)
allow(twitter_client).to receive(:update!)
stub_const("APP_CONFIG", {
'hostname' => 'example.com',
'https' => true,
'items_per_page' => 5,
'sharing' => {
'twitter' => {
'consumer_key' => 'AAA',
}
}
})
end
it "posts a shortened tweet" do
service.post(answer)
expect(twitter_client).to have_received(:update!).with("#{'q' * 123}… — #{'a' * 124}… https://example.com/#{user.screen_name}/a/#{answer.id}")
end
it "posts an un-shortened tweet" do
answer.question.content = 'Why are raccoons so good?'
answer.question.save!
answer.content = 'Because they are good cunes.'
answer.save!
service.post(answer)
expect(twitter_client).to have_received(:update!).with("#{answer.question.content}#{answer.content} https://example.com/#{user.screen_name}/a/#{answer.id}")
end
end
end