This new class replaces all existing server side message rendering helpers and is the new global entry point for such needs. All models with relevant fields now expose an instance of MessageRenderer for those. MessageRenderer acts as gateway between the existing processing solutions for markdown, mentions and tags and provides a very flexible interface for all output needs. This makes the API to obtain a message in a certain format clear. As a result of centralizing the processing a lot of duplication is eliminated. Centralizing the message processing also makes it clear where to change its behaviour, add new representations and what options are already available.
107 lines
2.9 KiB
Ruby
107 lines
2.9 KiB
Ruby
class Services::Twitter < Service
|
|
include Rails.application.routes.url_helpers
|
|
|
|
MAX_CHARACTERS = 140
|
|
SHORTENED_URL_LENGTH = 21
|
|
LINK_PATTERN = %r{https?://\S+}
|
|
|
|
def provider
|
|
"twitter"
|
|
end
|
|
|
|
def post post, url=''
|
|
Rails.logger.debug "event=post_to_service type=twitter sender_id=#{self.user_id}"
|
|
tweet = attempt_post post
|
|
post.tweet_id = tweet.id
|
|
post.save
|
|
end
|
|
|
|
def profile_photo_url
|
|
client.user(nickname).profile_image_url_https "original"
|
|
end
|
|
|
|
def delete_post post
|
|
if post.present? && post.tweet_id.present?
|
|
Rails.logger.debug "event=delete_from_service type=twitter sender_id=#{self.user_id}"
|
|
delete_from_twitter post.tweet_id
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def client
|
|
@client ||= Twitter::Client.new(
|
|
oauth_token: self.access_token,
|
|
oauth_token_secret: self.access_secret
|
|
)
|
|
end
|
|
|
|
def attempt_post post, retry_count=0
|
|
message = build_twitter_post post, retry_count
|
|
client.update message
|
|
rescue Twitter::Error::Forbidden => e
|
|
if ! e.message.include? 'is over 140' || retry_count == 20
|
|
raise e
|
|
else
|
|
attempt_post post, retry_count+1
|
|
end
|
|
end
|
|
|
|
def build_twitter_post post, retry_count=0
|
|
max_characters = MAX_CHARACTERS - retry_count
|
|
|
|
post_text = post.message.plain_text_without_markdown
|
|
truncate_and_add_post_link post, post_text, max_characters
|
|
end
|
|
|
|
def truncate_and_add_post_link post, post_text, max_characters
|
|
return post_text unless needs_link? post, post_text, max_characters
|
|
|
|
post_url = short_post_url(
|
|
post,
|
|
protocol: AppConfig.pod_uri.scheme,
|
|
host: AppConfig.pod_uri.authority
|
|
)
|
|
|
|
truncated_text = post_text.truncate max_characters - SHORTENED_URL_LENGTH + 1
|
|
truncated_text = restore_truncated_url truncated_text, post_text, max_characters
|
|
|
|
"#{truncated_text} #{post_url}"
|
|
end
|
|
|
|
def needs_link? post, post_text, max_characters
|
|
adjust_length_for_urls(post_text) > max_characters || post.photos.any?
|
|
end
|
|
|
|
def adjust_length_for_urls post_text
|
|
real_length = post_text.length
|
|
|
|
URI.extract(post_text, ['http','https']) do |url|
|
|
# add or subtract from real length - urls for tweets are always
|
|
# shortened to SHORTENED_URL_LENGTH
|
|
if url.length >= SHORTENED_URL_LENGTH
|
|
real_length -= url.length - SHORTENED_URL_LENGTH
|
|
else
|
|
real_length += SHORTENED_URL_LENGTH - url.length
|
|
end
|
|
end
|
|
|
|
real_length
|
|
end
|
|
|
|
def restore_truncated_url truncated_text, post_text, max_characters
|
|
return truncated_text if truncated_text !~ /#{LINK_PATTERN}\Z/
|
|
|
|
url = post_text.match(LINK_PATTERN, truncated_text.rindex('http'))[0]
|
|
truncated_text = post_text.truncate(
|
|
max_characters - SHORTENED_URL_LENGTH + 2,
|
|
separator: ' ', omission: ''
|
|
)
|
|
|
|
"#{truncated_text} #{url} ..."
|
|
end
|
|
|
|
def delete_from_twitter service_post_id
|
|
client.status_destroy service_post_id
|
|
end
|
|
end
|