diff options
Diffstat (limited to 'app/lib')
-rw-r--r-- | app/lib/exceptions.rb | 3 | ||||
-rw-r--r-- | app/lib/feed_manager.rb | 20 | ||||
-rw-r--r-- | app/lib/formatter.rb | 29 | ||||
-rw-r--r-- | app/lib/tag_manager.rb | 10 |
4 files changed, 51 insertions, 11 deletions
diff --git a/app/lib/exceptions.rb b/app/lib/exceptions.rb index 359228c29..200da9fe1 100644 --- a/app/lib/exceptions.rb +++ b/app/lib/exceptions.rb @@ -2,5 +2,6 @@ module Mastodon class Error < StandardError; end - class NotPermitted < Error; end + class NotPermittedError < Error; end + class ValidationError < Error; end end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 623a1af03..cd6ca1291 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -22,8 +22,18 @@ class FeedManager end def push(timeline_type, account, status) - redis.zadd(key(timeline_type, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id) - trim(timeline_type, account.id) + timeline_key = key(timeline_type, account.id) + + if status.reblog? + # If the original status is within 40 statuses from top, do not re-insert it into the feed + rank = redis.zrevrank(timeline_key, status.reblog_of_id) + return if !rank.nil? && rank < 40 + redis.zadd(timeline_key, status.id, status.reblog_of_id) + else + redis.zadd(timeline_key, status.id, status.id) + trim(timeline_type, account.id) + end + broadcast(account.id, event: 'update', payload: inline_render(account, 'api/v1/statuses/show', status)) end @@ -42,7 +52,7 @@ class FeedManager timeline_key = key(:home, into_account.id) from_account.statuses.limit(MAX_ITEMS).each do |status| - next if filter?(:home, status, into_account) + next if status.direct_visibility? || filter?(:home, status, into_account) redis.zadd(timeline_key, status.id, status.id) end @@ -85,6 +95,8 @@ class FeedManager end def filter_from_home?(status, receiver) + return true if receiver.muting?(status.account) + should_filter = false if status.reply? && status.in_reply_to_id.nil? @@ -95,6 +107,8 @@ class FeedManager should_filter &&= !(status.account_id == status.in_reply_to_account_id) # and it's not a self-reply elsif status.reblog? # Filter out a reblog should_filter = receiver.blocking?(status.reblog.account) # if I'm blocking the reblogged person + should_filter ||= receiver.muting?(status.reblog.account) # or muting that person + should_filter ||= status.reblog.account.blocking?(receiver) # or if the author of the reblogged status is blocking me end should_filter ||= receiver.blocking?(status.mentions.map(&:account_id)) # or if it mentions someone I blocked diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 044407a6c..da7ad2027 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -24,7 +24,12 @@ class Formatter end def reformat(html) - sanitize(html, tags: %w(a br p), attributes: %w(href rel)) + sanitize(html, tags: %w(a br p span), attributes: %w(href rel class)) + end + + def plaintext(status) + return status.text if status.local? + strip_tags(status.text) end def simplified_format(account) @@ -32,6 +37,7 @@ class Formatter html = encode(account.note) html = link_urls(html) + html = link_accounts(html) html = link_hashtags(html) html.html_safe # rubocop:disable Rails/OutputSafety @@ -44,20 +50,31 @@ class Formatter end def link_urls(html) - html.gsub(URI.regexp(%w(http https))) do |match| - link_html(match) - end + Twitter::Autolink.auto_link_urls(html, url_target: '_blank', + link_attribute_block: lambda { |_, a| a[:rel] << ' noopener' }, + link_text_block: lambda { |_, text| link_html(text) }) end def link_mentions(html, mentions) html.gsub(Account::MENTION_RE) do |match| acct = Account::MENTION_RE.match(match)[1] - mention = mentions.find { |item| item.account.acct.casecmp(acct).zero? } + mention = mentions.find { |item| TagManager.instance.same_acct?(item.account.acct, acct) } mention.nil? ? match : mention_html(match, mention.account) end end + def link_accounts(html) + html.gsub(Account::MENTION_RE) do |match| + acct = Account::MENTION_RE.match(match)[1] + username, domain = acct.split('@') + domain = nil if TagManager.instance.local_domain?(domain) + account = Account.find_remote(username, domain) + + account.nil? ? match : mention_html(match, account) + end + end + def link_hashtags(html) html.gsub(Tag::HASHTAG_RE) do |match| hashtag_html(match) @@ -70,7 +87,7 @@ class Formatter suffix = url[prefix.length + 30..-1] cutoff = url[prefix.length..-1].length > 30 - "<a rel=\"nofollow noopener\" target=\"_blank\" href=\"#{url}\"><span class=\"invisible\">#{prefix}</span><span class=\"#{cutoff ? 'ellipsis' : ''}\">#{text}</span><span class=\"invisible\">#{suffix}</span></a>" + "<span class=\"invisible\">#{prefix}</span><span class=\"#{cutoff ? 'ellipsis' : ''}\">#{text}</span><span class=\"invisible\">#{suffix}</span>" end def hashtag_html(match) diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index 9fef70fda..2a5e7a409 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -60,6 +60,12 @@ class TagManager domain.nil? || domain.gsub(/[\/]/, '').casecmp(Rails.configuration.x.local_domain).zero? end + def same_acct?(canonical, needle) + return true if canonical.casecmp(needle).zero? + username, domain = needle.split('@') + local_domain?(domain) && canonical.casecmp(username).zero? + end + def local_url?(url) uri = Addressable::URI.parse(url) domain = uri.host + (uri.port ? ":#{uri.port}" : '') @@ -82,7 +88,9 @@ class TagManager case target.object_type when :person - account_url(target) + short_account_url(target) + when :note, :comment, :activity + short_account_status_url(target.account, target) else account_stream_entry_url(target.account, target.stream_entry) end |