Refactored generation of unique tags, URIs and object URLs into own classes,
as well as formatting of content
This commit is contained in:
		@@ -1,54 +1,4 @@
 | 
				
			|||||||
module ApplicationHelper
 | 
					module ApplicationHelper
 | 
				
			||||||
  def unique_tag(date, id, type)
 | 
					 | 
				
			||||||
    "tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def unique_tag_to_local_id(tag, expected_type)
 | 
					 | 
				
			||||||
    matches = Regexp.new("objectId=([\\d]+):objectType=#{expected_type}").match(tag)
 | 
					 | 
				
			||||||
    return matches[1] unless matches.nil?
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def local_id?(id)
 | 
					 | 
				
			||||||
    id.start_with?("tag:#{Rails.configuration.x.local_domain}")
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def content_for_status(actual_status)
 | 
					 | 
				
			||||||
    if actual_status.local?
 | 
					 | 
				
			||||||
      linkify(actual_status)
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      sanitize(actual_status.content, tags: %w(a br p), attributes: %w(href rel))
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def account_from_mentions(search_string, mentions)
 | 
					 | 
				
			||||||
    mentions.each { |x| return x.account if x.account.acct.eql?(search_string) }
 | 
					 | 
				
			||||||
    nil
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # If that was unsuccessful, try fetching user from db separately
 | 
					 | 
				
			||||||
    # But this shouldn't ever happen if the mentions were created correctly!
 | 
					 | 
				
			||||||
    # username, domain = search_string.split('@')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # if domain == Rails.configuration.x.local_domain
 | 
					 | 
				
			||||||
    #   account = Account.find_local(username)
 | 
					 | 
				
			||||||
    # else
 | 
					 | 
				
			||||||
    #   account = Account.find_remote(username, domain)
 | 
					 | 
				
			||||||
    # end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # account
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def linkify(status)
 | 
					 | 
				
			||||||
    auto_link(HTMLEntities.new.encode(status.text), link: :urls, html: { rel: 'nofollow noopener' }).gsub(Account::MENTION_RE) do |m|
 | 
					 | 
				
			||||||
      account = account_from_mentions(Account::MENTION_RE.match(m)[1], status.mentions)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      unless account.nil?
 | 
					 | 
				
			||||||
        "#{m.split('@').first}<a href=\"#{url_for_target(account)}\" class=\"mention\">@<span>#{account.acct}</span></a>"
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        m
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end.html_safe
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def active_nav_class(path)
 | 
					  def active_nav_class(path)
 | 
				
			||||||
    current_page?(path) ? 'active' : ''
 | 
					    current_page?(path) ? 'active' : ''
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ module AtomBuilderHelper
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def unique_id(xml, date, id, type)
 | 
					  def unique_id(xml, date, id, type)
 | 
				
			||||||
    xml.id_ unique_tag(date, id, type)
 | 
					    xml.id_ TagManager.instance.unique_tag(date, id, type)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def simple_id(xml, id)
 | 
					  def simple_id(xml, id)
 | 
				
			||||||
@@ -97,32 +97,8 @@ module AtomBuilderHelper
 | 
				
			|||||||
    xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' })
 | 
					    xml['thr'].send('in-reply-to', { ref: uri, href: url, type: 'text/html' })
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def uri_for_target(target)
 | 
					 | 
				
			||||||
    if target.local?
 | 
					 | 
				
			||||||
      if target.object_type == :person
 | 
					 | 
				
			||||||
        account_url(target)
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      target.uri
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def url_for_target(target)
 | 
					 | 
				
			||||||
    if target.local?
 | 
					 | 
				
			||||||
      if target.object_type == :person
 | 
					 | 
				
			||||||
        account_url(target)
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        account_stream_entry_url(target.account, target.stream_entry)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      target.url
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def link_mention(xml, account)
 | 
					  def link_mention(xml, account)
 | 
				
			||||||
    xml.link(rel: 'mentioned', href: uri_for_target(account))
 | 
					    xml.link(rel: 'mentioned', href: TagManager.instance.uri_for(account))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def link_enclosure(xml, media)
 | 
					  def link_enclosure(xml, media)
 | 
				
			||||||
@@ -145,7 +121,7 @@ module AtomBuilderHelper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def conditionally_formatted(activity)
 | 
					  def conditionally_formatted(activity)
 | 
				
			||||||
    if activity.is_a?(Status)
 | 
					    if activity.is_a?(Status)
 | 
				
			||||||
      content_for_status(activity.reblog? ? activity.reblog : activity)
 | 
					      Formatter.instance.format(activity.reblog? ? activity.reblog : activity)
 | 
				
			||||||
    elsif activity.nil?
 | 
					    elsif activity.nil?
 | 
				
			||||||
      nil
 | 
					      nil
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
@@ -155,11 +131,11 @@ module AtomBuilderHelper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def include_author(xml, account)
 | 
					  def include_author(xml, account)
 | 
				
			||||||
    object_type      xml, :person
 | 
					    object_type      xml, :person
 | 
				
			||||||
    uri              xml, uri_for_target(account)
 | 
					    uri              xml, TagManager.instance.uri_for(account)
 | 
				
			||||||
    name             xml, account.username
 | 
					    name             xml, account.username
 | 
				
			||||||
    email            xml, account.local? ? "#{account.acct}@#{Rails.configuration.x.local_domain}" : account.acct
 | 
					    email            xml, account.local? ? "#{account.acct}@#{Rails.configuration.x.local_domain}" : account.acct
 | 
				
			||||||
    summary          xml, account.note
 | 
					    summary          xml, account.note
 | 
				
			||||||
    link_alternate   xml, url_for_target(account)
 | 
					    link_alternate   xml, TagManager.instance.url_for(account)
 | 
				
			||||||
    link_avatar      xml, account
 | 
					    link_avatar      xml, account
 | 
				
			||||||
    portable_contact xml, account
 | 
					    portable_contact xml, account
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -176,7 +152,7 @@ module AtomBuilderHelper
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # Comments need thread element
 | 
					    # Comments need thread element
 | 
				
			||||||
    if stream_entry.threaded?
 | 
					    if stream_entry.threaded?
 | 
				
			||||||
      in_reply_to xml, uri_for_target(stream_entry.thread), url_for_target(stream_entry.thread)
 | 
					      in_reply_to xml, TagManager.instance.uri_for(stream_entry.thread), TagManager.instance.url_for(stream_entry.thread)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if stream_entry.targeted?
 | 
					    if stream_entry.targeted?
 | 
				
			||||||
@@ -185,9 +161,9 @@ module AtomBuilderHelper
 | 
				
			|||||||
          include_author xml, stream_entry.target
 | 
					          include_author xml, stream_entry.target
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
          object_type    xml, stream_entry.target.object_type
 | 
					          object_type    xml, stream_entry.target.object_type
 | 
				
			||||||
          simple_id      xml, uri_for_target(stream_entry.target)
 | 
					          simple_id      xml, TagManager.instance.uri_for(stream_entry.target)
 | 
				
			||||||
          title          xml, stream_entry.target.title
 | 
					          title          xml, stream_entry.target.title
 | 
				
			||||||
          link_alternate xml, url_for_target(stream_entry.target)
 | 
					          link_alternate xml, TagManager.instance.url_for(stream_entry.target)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Statuses have content and author
 | 
					        # Statuses have content and author
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,15 @@
 | 
				
			|||||||
 | 
					require 'singleton'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FeedManager
 | 
					class FeedManager
 | 
				
			||||||
 | 
					  include Singleton
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  MAX_ITEMS = 800
 | 
					  MAX_ITEMS = 800
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def self.key(type, id)
 | 
					  def key(type, id)
 | 
				
			||||||
    "feed:#{type}:#{id}"
 | 
					    "feed:#{type}:#{id}"
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def self.filter_status?(status, follower)
 | 
					  def filter_status?(status, follower)
 | 
				
			||||||
    replied_to_user = status.reply? ? status.thread.account : nil
 | 
					    replied_to_user = status.reply? ? status.thread.account : nil
 | 
				
			||||||
    (status.reply? && !(follower.id = replied_to_user.id || follower.following?(replied_to_user)))
 | 
					    (status.reply? && !(follower.id = replied_to_user.id || follower.following?(replied_to_user)))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								app/lib/formatter.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/lib/formatter.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					require 'singleton'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Formatter
 | 
				
			||||||
 | 
					  include Singleton
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  include ActionView::Helpers::TextHelper
 | 
				
			||||||
 | 
					  include ActionView::Helpers::SanitizeHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def format(status)
 | 
				
			||||||
 | 
					    return reformat(status) unless status.local?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    html = status.text
 | 
				
			||||||
 | 
					    html = encode(html)
 | 
				
			||||||
 | 
					    html = link_urls(html)
 | 
				
			||||||
 | 
					    html = link_mentions(html, status.mentions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    html.html_safe
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def reformat(status)
 | 
				
			||||||
 | 
					    sanitize(status.content, tags: %w(a br p), attributes: %w(href rel))
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def encode(html)
 | 
				
			||||||
 | 
					    HTMLEntities.new.encode(html)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def link_urls(html)
 | 
				
			||||||
 | 
					    auto_link(html, link: :urls, html: { rel: 'nofollow noopener' })
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def link_mentions(html, mentions)
 | 
				
			||||||
 | 
					    html.gsub(Account::MENTION_RE) do |match|
 | 
				
			||||||
 | 
					      acct    = Account::MENTION_RE.match(match)[1]
 | 
				
			||||||
 | 
					      mention = mentions.find { |mention| mention.account.acct.eql?(acct) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return match if mention.nil?
 | 
				
			||||||
 | 
					      mention_html(match, mention.account)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def mention_html(match, account)
 | 
				
			||||||
 | 
					    "#{match.split('@').first}<a href=\"#{TagManager.instance.url_for(account)}\" class=\"mention\">@<span>#{account.acct}</span></a>"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										41
									
								
								app/lib/tag_manager.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/lib/tag_manager.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					require 'singleton'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TagManager
 | 
				
			||||||
 | 
					  include Singleton
 | 
				
			||||||
 | 
					  include RoutingHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def unique_tag(date, id, type)
 | 
				
			||||||
 | 
					    "tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def unique_tag_to_local_id(tag, expected_type)
 | 
				
			||||||
 | 
					    matches = Regexp.new("objectId=([\\d]+):objectType=#{expected_type}").match(tag)
 | 
				
			||||||
 | 
					    return matches[1] unless matches.nil?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def local_id?(id)
 | 
				
			||||||
 | 
					    id.start_with?("tag:#{Rails.configuration.x.local_domain}")
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def uri_for(target)
 | 
				
			||||||
 | 
					    return target.uri if target.respond_to?(:local?) && !target.local?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case target.object_type
 | 
				
			||||||
 | 
					    when :person
 | 
				
			||||||
 | 
					      account_url(target)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def url_for(target)
 | 
				
			||||||
 | 
					    return target.url if target.respond_to?(:local?) && !target.local?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case target.object_type
 | 
				
			||||||
 | 
					    when :person
 | 
				
			||||||
 | 
					      account_url(target)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      account_stream_entry_url(target.account, target.stream_entry)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -21,7 +21,7 @@ class Feed
 | 
				
			|||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def key
 | 
					  def key
 | 
				
			||||||
    FeedManager.key(@type, @account.id)
 | 
					    FeedManager.instance.key(@type, @account.id)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def redis
 | 
					  def redis
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ class FanOutOnWriteService < BaseService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def deliver_to_followers(status)
 | 
					  def deliver_to_followers(status)
 | 
				
			||||||
    status.account.followers.each do |follower|
 | 
					    status.account.followers.each do |follower|
 | 
				
			||||||
      next if !follower.local? || FeedManager.filter_status?(status, follower)
 | 
					      next if !follower.local? || FeedManager.instance.filter_status?(status, follower)
 | 
				
			||||||
      push(:home, follower, status)
 | 
					      push(:home, follower, status)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -29,16 +29,16 @@ class FanOutOnWriteService < BaseService
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def push(type, receiver, status)
 | 
					  def push(type, receiver, status)
 | 
				
			||||||
    redis.zadd(FeedManager.key(type, receiver.id), status.id, status.id)
 | 
					    redis.zadd(FeedManager.instance.key(type, receiver.id), status.id, status.id)
 | 
				
			||||||
    trim(type, receiver)
 | 
					    trim(type, receiver)
 | 
				
			||||||
    ActionCable.server.broadcast("timeline:#{receiver.id}", type: 'update', timeline: type, message: inline_render(receiver, status))
 | 
					    ActionCable.server.broadcast("timeline:#{receiver.id}", type: 'update', timeline: type, message: inline_render(receiver, status))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def trim(type, receiver)
 | 
					  def trim(type, receiver)
 | 
				
			||||||
    return unless redis.zcard(FeedManager.key(type, receiver.id)) > FeedManager::MAX_ITEMS
 | 
					    return unless redis.zcard(FeedManager.instance.key(type, receiver.id)) > FeedManager::MAX_ITEMS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    last = redis.zrevrange(FeedManager.key(type, receiver.id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1)
 | 
					    last = redis.zrevrange(FeedManager.instance.key(type, receiver.id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1)
 | 
				
			||||||
    redis.zremrangebyscore(FeedManager.key(type, receiver.id), '-inf', "(#{last.last}")
 | 
					    redis.zremrangebyscore(FeedManager.instance.key(type, receiver.id), '-inf', "(#{last.last}")
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def redis
 | 
					  def redis
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,8 @@ class PrecomputeFeedService < BaseService
 | 
				
			|||||||
    instant_return = []
 | 
					    instant_return = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Status.send("as_#{type}_timeline", account).order('created_at desc').limit(FeedManager::MAX_ITEMS).each do |status|
 | 
					    Status.send("as_#{type}_timeline", account).order('created_at desc').limit(FeedManager::MAX_ITEMS).each do |status|
 | 
				
			||||||
      next if type == :home && FeedManager.filter_status?(status, account)
 | 
					      next if type == :home && FeedManager.instance.filter_status?(status, account)
 | 
				
			||||||
      redis.zadd(FeedManager.key(type, account.id), status.id, status.id)
 | 
					      redis.zadd(FeedManager.instance.key(type, account.id), status.id, status.id)
 | 
				
			||||||
      instant_return << status unless instant_return.size > limit
 | 
					      instant_return << status unless instant_return.size > limit
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,10 +39,10 @@ class ProcessFeedService < BaseService
 | 
				
			|||||||
    # Also record all media attachments for the status and for the reblogged status if present
 | 
					    # Also record all media attachments for the status and for the reblogged status if present
 | 
				
			||||||
    unless status.new_record?
 | 
					    unless status.new_record?
 | 
				
			||||||
      record_remote_mentions(status, entry.xpath('./xmlns:link[@rel="mentioned"]'))
 | 
					      record_remote_mentions(status, entry.xpath('./xmlns:link[@rel="mentioned"]'))
 | 
				
			||||||
      
 | 
					
 | 
				
			||||||
      process_attachments(entry, status)
 | 
					      process_attachments(entry, status)
 | 
				
			||||||
      process_attachments(entry.xpath('./activity:object'), status.reblog) if status.reblog?
 | 
					      process_attachments(entry.xpath('./activity:object'), status.reblog) if status.reblog?
 | 
				
			||||||
      
 | 
					
 | 
				
			||||||
      DistributionWorker.perform_async(status.id)
 | 
					      DistributionWorker.perform_async(status.id)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -112,8 +112,8 @@ class ProcessFeedService < BaseService
 | 
				
			|||||||
  def find_original_status(_xml, id)
 | 
					  def find_original_status(_xml, id)
 | 
				
			||||||
    return nil if id.nil?
 | 
					    return nil if id.nil?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if local_id?(id)
 | 
					    if TagManager.instance.local_id?(id)
 | 
				
			||||||
      Status.find(unique_tag_to_local_id(id, 'Status'))
 | 
					      Status.find(TagManager.instance.unique_tag_to_local_id(id, 'Status'))
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      Status.find_by(uri: id)
 | 
					      Status.find_by(uri: id)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ class ProcessInteractionService < BaseService
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def mentions_account?(xml, account)
 | 
					  def mentions_account?(xml, account)
 | 
				
			||||||
    xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]').each { |mention_link| return true if mention_link.attribute('href').value == url_for_target(account) }
 | 
					    xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]').each { |mention_link| return true if mention_link.attribute('href').value == TagManager.instance.url_for(account) }
 | 
				
			||||||
    false
 | 
					    false
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -85,7 +85,7 @@ class ProcessInteractionService < BaseService
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def status(xml)
 | 
					  def status(xml)
 | 
				
			||||||
    Status.find(unique_tag_to_local_id(activity_id(xml), 'Status'))
 | 
					    Status.find(TagManager.instance.unique_tag_to_local_id(activity_id(xml), 'Status'))
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def activity_id(xml)
 | 
					  def activity_id(xml)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@ class RemoveStatusService < BaseService
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def unpush(type, receiver, status)
 | 
					  def unpush(type, receiver, status)
 | 
				
			||||||
    redis.zremrangebyscore(FeedManager.key(type, receiver.id), status.id, status.id)
 | 
					    redis.zremrangebyscore(FeedManager.instance.key(type, receiver.id), status.id, status.id)
 | 
				
			||||||
    ActionCable.server.broadcast("timeline:#{receiver.id}", type: 'delete', id: status.id)
 | 
					    ActionCable.server.broadcast("timeline:#{receiver.id}", type: 'delete', id: status.id)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
  .account-grid-card__header
 | 
					  .account-grid-card__header
 | 
				
			||||||
    .avatar= image_tag account.avatar.url(:medium)
 | 
					    .avatar= image_tag account.avatar.url(:medium)
 | 
				
			||||||
    .name
 | 
					    .name
 | 
				
			||||||
      = link_to url_for_target(account) do
 | 
					      = link_to TagManager.instance.url_for(account) do
 | 
				
			||||||
        %span.display_name= display_name(account)
 | 
					        %span.display_name= display_name(account)
 | 
				
			||||||
        %span.username= "@#{account.acct}"
 | 
					        %span.username= "@#{account.acct}"
 | 
				
			||||||
  %p.note= truncate(strip_tags(account.note), length: 150)
 | 
					  %p.note= truncate(strip_tags(account.note), length: 150)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ Nokogiri::XML::Builder.new do |xml|
 | 
				
			|||||||
      include_author xml, @account
 | 
					      include_author xml, @account
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    link_alternate xml, url_for_target(@account)
 | 
					    link_alternate xml, TagManager.instance.url_for(@account)
 | 
				
			||||||
    link_self      xml, account_url(@account, format: 'atom')
 | 
					    link_self      xml, account_url(@account, format: 'atom')
 | 
				
			||||||
    link_hub       xml, Rails.configuration.x.hub_url
 | 
					    link_hub       xml, Rails.configuration.x.hub_url
 | 
				
			||||||
    link_salmon    xml, api_salmon_url(@account.id)
 | 
					    link_salmon    xml, api_salmon_url(@account.id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ object @account
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
attributes :id, :username, :acct, :display_name, :note
 | 
					attributes :id, :username, :acct, :display_name, :note
 | 
				
			||||||
 | 
					
 | 
				
			||||||
node(:url)             { |account| url_for_target(account) }
 | 
					node(:url)             { |account| TagManager.instance.url_for(account) }
 | 
				
			||||||
node(:avatar)          { |account| full_asset_url(account.avatar.url(:large, false)) }
 | 
					node(:avatar)          { |account| full_asset_url(account.avatar.url(:large, false)) }
 | 
				
			||||||
node(:followers_count) { |account| account.followers.count }
 | 
					node(:followers_count) { |account| account.followers.count }
 | 
				
			||||||
node(:following_count) { |account| account.following.count }
 | 
					node(:following_count) { |account| account.following.count }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
object @status
 | 
					object @status
 | 
				
			||||||
attributes :id, :created_at, :in_reply_to_id
 | 
					attributes :id, :created_at, :in_reply_to_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
node(:uri)              { |status| uri_for_target(status) }
 | 
					node(:uri)              { |status| TagManager.instance.uri_for(status) }
 | 
				
			||||||
node(:content)          { |status| content_for_status(status) }
 | 
					node(:content)          { |status| Formatter.instance.format(status) }
 | 
				
			||||||
node(:url)              { |status| url_for_target(status) }
 | 
					node(:url)              { |status| TagManager.instance.url_for(status) }
 | 
				
			||||||
node(:reblogs_count)    { |status| status.reblogs_count }
 | 
					node(:reblogs_count)    { |status| status.reblogs_count }
 | 
				
			||||||
node(:favourites_count) { |status| status.favourites_count }
 | 
					node(:favourites_count) { |status| status.favourites_count }
 | 
				
			||||||
node(:favourited)       { |status| current_account.favourited?(status) }
 | 
					node(:favourited)       { |status| current_account.favourited?(status) }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,4 +2,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<%= @account.acct %> is now following you!
 | 
					<%= @account.acct %> is now following you!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<%= url_for_target(@account) %>
 | 
					<%= TagManager.instance.url_for(@account) %>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ You were mentioned by <%= @status.account.acct %> in:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<%= strip_tags(@status.content) %>
 | 
					<%= strip_tags(@status.content) %>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<%= url_for_target(@status) %>
 | 
					<%= TagManager.instance.url_for(@status) %>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,4 +2,4 @@
 | 
				
			|||||||
  .content
 | 
					  .content
 | 
				
			||||||
    %strong= link_to follow.account.acct, account_path(follow.account)
 | 
					    %strong= link_to follow.account.acct, account_path(follow.account)
 | 
				
			||||||
    is now following
 | 
					    is now following
 | 
				
			||||||
    %strong= link_to follow.target_account.acct, url_for_target(follow.target_account)
 | 
					    %strong= link_to follow.target_account.acct, TagManager.instance.url_for(follow.target_account)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@
 | 
				
			|||||||
    .pre-header
 | 
					    .pre-header
 | 
				
			||||||
      %i.fa.fa-retweet
 | 
					      %i.fa.fa-retweet
 | 
				
			||||||
      Shared by
 | 
					      Shared by
 | 
				
			||||||
      = link_to display_name(status.account), url_for_target(status.account), class: 'name'
 | 
					      = link_to display_name(status.account), TagManager.instance.url_for(status.account), class: 'name'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .entry__container
 | 
					  .entry__container
 | 
				
			||||||
    .avatar
 | 
					    .avatar
 | 
				
			||||||
@@ -21,10 +21,10 @@
 | 
				
			|||||||
    .entry__container__container
 | 
					    .entry__container__container
 | 
				
			||||||
      .header
 | 
					      .header
 | 
				
			||||||
        .header__left
 | 
					        .header__left
 | 
				
			||||||
          = link_to url_for_target(proper_status(status).account), class: 'name' do
 | 
					          = link_to TagManager.instance.url_for(proper_status(status).account), class: 'name' do
 | 
				
			||||||
            %strong= display_name(proper_status(status).account)
 | 
					            %strong= display_name(proper_status(status).account)
 | 
				
			||||||
            = "@#{proper_status(status).account.acct}"
 | 
					            = "@#{proper_status(status).account.acct}"
 | 
				
			||||||
          = link_to url_for_target(proper_status(status)), class: 'time' do
 | 
					          = link_to TagManager.instance.url_for(proper_status(status)), class: 'time' do
 | 
				
			||||||
            %span{ title: proper_status(status).created_at }
 | 
					            %span{ title: proper_status(status).created_at }
 | 
				
			||||||
              = relative_time(proper_status(status).created_at)
 | 
					              = relative_time(proper_status(status).created_at)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +36,7 @@
 | 
				
			|||||||
            %i.fa.fa-star
 | 
					            %i.fa.fa-star
 | 
				
			||||||
            %span.counter-number= proper_status(status).favourites_count
 | 
					            %span.counter-number= proper_status(status).favourites_count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .content= content_for_status(proper_status(status))
 | 
					      .content= Formatter.instance.format(proper_status(status))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      %ul.media-attachments
 | 
					      %ul.media-attachments
 | 
				
			||||||
        - status.media_attachments.each do |media|
 | 
					        - status.media_attachments.each do |media|
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
Nokogiri::XML::Builder.new do |xml|
 | 
					Nokogiri::XML::Builder.new do |xml|
 | 
				
			||||||
  xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
 | 
					  xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
 | 
				
			||||||
    xml.Subject @canonical_account_uri
 | 
					    xml.Subject @canonical_account_uri
 | 
				
			||||||
    xml.Alias url_for_target(@account)
 | 
					    xml.Alias TagManager.instance.url_for(@account)
 | 
				
			||||||
    xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: url_for_target(@account))
 | 
					    xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: TagManager.instance.url_for(@account))
 | 
				
			||||||
    xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom'))
 | 
					    xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom'))
 | 
				
			||||||
    xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
 | 
					    xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
 | 
				
			||||||
    xml.Link(rel: 'magic-public-key', href: @magic_key)
 | 
					    xml.Link(rel: 'magic-public-key', href: @magic_key)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,15 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe Oauth::ApplicationsController, type: :controller do
 | 
					RSpec.describe Oauth::ApplicationsController, type: :controller do
 | 
				
			||||||
 | 
					  before do
 | 
				
			||||||
 | 
					    sign_in Fabricate(:user), scope: :user
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe 'GET #index' do
 | 
					  describe 'GET #index' do
 | 
				
			||||||
    it 'returns http success'
 | 
					    it 'returns http success' do
 | 
				
			||||||
 | 
					      get :index
 | 
				
			||||||
 | 
					      expect(response).to have_http_status(:success)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe 'POST #create' do
 | 
					  describe 'POST #create' do
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,59 +1,5 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe ApplicationHelper, type: :helper do
 | 
					RSpec.describe ApplicationHelper, type: :helper do
 | 
				
			||||||
  let(:local_domain) { Rails.configuration.x.local_domain }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe '#unique_tag' do
 | 
					 | 
				
			||||||
    it 'returns a string' do
 | 
					 | 
				
			||||||
      expect(helper.unique_tag(Time.now, 12, 'Status')).to be_a String
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#unique_tag_to_local_id' do
 | 
					 | 
				
			||||||
    it 'returns the ID part' do
 | 
					 | 
				
			||||||
      expect(helper.unique_tag_to_local_id("tag:#{local_domain};objectId=12:objectType=Status", 'Status')).to eql '12'
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#local_id?' do
 | 
					 | 
				
			||||||
    it 'returns true for a local ID' do
 | 
					 | 
				
			||||||
      expect(helper.local_id?("tag:#{local_domain};objectId=12:objectType=Status")).to be true
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it 'returns false for a foreign ID' do
 | 
					 | 
				
			||||||
      expect(helper.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#linkify' do
 | 
					 | 
				
			||||||
    let(:alice) { Fabricate(:account, username: 'alice') }
 | 
					 | 
				
			||||||
    let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', url: 'http://example.com/bob') }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it 'turns mention of remote user into link' do
 | 
					 | 
				
			||||||
      status = Fabricate(:status, text: 'Hello @bob@example.com', account: bob)
 | 
					 | 
				
			||||||
      status.mentions.create(account: bob)
 | 
					 | 
				
			||||||
      expect(helper.linkify(status)).to match('<a href="http://example.com/bob" class="mention">@<span>bob@example.com</span></a>')
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it 'turns mention of local user into link' do
 | 
					 | 
				
			||||||
      status = Fabricate(:status, text: 'Hello @alice', account: bob)
 | 
					 | 
				
			||||||
      status.mentions.create(account: alice)
 | 
					 | 
				
			||||||
      expect(helper.linkify(status)).to match('<a href="http://test.host/users/alice" class="mention">@<span>alice</span></a>')
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it 'leaves mention of unresolvable user alone' do
 | 
					 | 
				
			||||||
      status = Fabricate(:status, text: 'Hello @foo', account: bob)
 | 
					 | 
				
			||||||
      expect(helper.linkify(status)).to match('Hello @foo')
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#account_from_mentions' do
 | 
					 | 
				
			||||||
    let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') }
 | 
					 | 
				
			||||||
    let(:status) { Fabricate(:status, text: 'Hello @bob@example.com', account: bob) }
 | 
					 | 
				
			||||||
    let(:mentions) { [Mention.create(status: status, account: bob)] }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    it 'returns account' do
 | 
					 | 
				
			||||||
      expect(helper.account_from_mentions('bob@example.com', mentions)).to eq bob
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
 | 
				
			|||||||
  describe '#unique_id' do
 | 
					  describe '#unique_id' do
 | 
				
			||||||
    it 'creates an id' do
 | 
					    it 'creates an id' do
 | 
				
			||||||
      time = Time.now
 | 
					      time = Time.now
 | 
				
			||||||
      expect(used_in_builder { |xml| helper.unique_id(xml, time, 1, 'Status') }).to match "<id>#{helper.unique_tag(time, 1, 'Status')}</id>"
 | 
					      expect(used_in_builder { |xml| helper.unique_id(xml, time, 1, 'Status') }).to match "<id>#{TagManager.instance.unique_tag(time, 1, 'Status')}</id>"
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,18 +146,10 @@ RSpec.describe AtomBuilderHelper, type: :helper do
 | 
				
			|||||||
    let(:account) { Fabricate(:account, username: 'alice') }
 | 
					    let(:account) { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it 'creates a link' do
 | 
					    it 'creates a link' do
 | 
				
			||||||
      expect(used_in_builder { |xml| helper.link_mention(xml, account) }).to match '<link rel="mentioned" href="http://test.host/users/alice"/>'
 | 
					      expect(used_in_builder { |xml| helper.link_mention(xml, account) }).to match '<link rel="mentioned" href="https://cb6e6126.ngrok.io/users/alice"/>'
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe '#disambiguate_uri' do
 | 
					 | 
				
			||||||
    pending
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#disambiguate_url' do
 | 
					 | 
				
			||||||
    pending
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe '#include_author' do
 | 
					  describe '#include_author' do
 | 
				
			||||||
    pending
 | 
					    pending
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								spec/lib/feed_manager_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								spec/lib/feed_manager_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe FeedManager do
 | 
				
			||||||
 | 
					  describe '#key' do
 | 
				
			||||||
 | 
					    subject { FeedManager.instance.key(:home, 1) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns a string' do
 | 
				
			||||||
 | 
					      expect(subject).to be_a String
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#filter_status?' do
 | 
				
			||||||
 | 
					    let(:followee) { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
 | 
					    let(:status)   { Fabricate(:status, text: 'Hello world', account: followee) }
 | 
				
			||||||
 | 
					    let(:follower) { Fabricate(:account, username: 'bob') }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subject { FeedManager.instance.filter_status?(status, follower) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns a boolean value' do
 | 
				
			||||||
 | 
					      expect(subject).to be false
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										39
									
								
								spec/lib/formatter_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								spec/lib/formatter_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe Formatter do
 | 
				
			||||||
 | 
					  let(:account)       { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
 | 
					  let(:local_status)  { Fabricate(:status, text: 'Hello world http://google.com', account: account) }
 | 
				
			||||||
 | 
					  let(:remote_status) { Fabricate(:status, text: '<script>alert("Hello")</script> Beep boop', uri: 'beepboop', account: account) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#format' do
 | 
				
			||||||
 | 
					    subject { Formatter.instance.format(local_status) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns a string' do
 | 
				
			||||||
 | 
					      expect(subject).to be_a String
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'contains plain text' do
 | 
				
			||||||
 | 
					      expect(subject).to match('Hello world')
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'contains a link' do
 | 
				
			||||||
 | 
					      expect(subject).to match('<a rel="nofollow noopener" href="http://google.com">http://google.com</a>')
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#reformat' do
 | 
				
			||||||
 | 
					    subject { Formatter.instance.format(remote_status) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns a string' do
 | 
				
			||||||
 | 
					      expect(subject).to be_a String
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'contains plain text' do
 | 
				
			||||||
 | 
					      expect(subject).to match('Beep boop')
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'does not contain scripts' do
 | 
				
			||||||
 | 
					      expect(subject).to_not match('<script>alert("Hello")</script>')
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										107
									
								
								spec/lib/tag_manager_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								spec/lib/tag_manager_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe TagManager do
 | 
				
			||||||
 | 
					  let(:local_domain) { Rails.configuration.x.local_domain }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#unique_tag' do
 | 
				
			||||||
 | 
					    it 'returns a string' do
 | 
				
			||||||
 | 
					      expect(TagManager.instance.unique_tag(Time.now, 12, 'Status')).to be_a String
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#unique_tag_to_local_id' do
 | 
				
			||||||
 | 
					    it 'returns the ID part' do
 | 
				
			||||||
 | 
					      expect(TagManager.instance.unique_tag_to_local_id("tag:#{local_domain};objectId=12:objectType=Status", 'Status')).to eql '12'
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#local_id?' do
 | 
				
			||||||
 | 
					    it 'returns true for a local ID' do
 | 
				
			||||||
 | 
					      expect(TagManager.instance.local_id?("tag:#{local_domain};objectId=12:objectType=Status")).to be true
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns false for a foreign ID' do
 | 
				
			||||||
 | 
					      expect(TagManager.instance.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#uri_for' do
 | 
				
			||||||
 | 
					    let(:alice)  { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
 | 
					    let(:bob)    { Fabricate(:account, username: 'bob') }
 | 
				
			||||||
 | 
					    let(:status) { Fabricate(:status, text: 'Hello world', account: alice) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subject { TagManager.instance.uri_for(target) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Account' do
 | 
				
			||||||
 | 
					      let(:target) { alice }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a string' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Status' do
 | 
				
			||||||
 | 
					      let(:target) { status }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a string' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Follow' do
 | 
				
			||||||
 | 
					      let(:target) { Fabricate(:follow, account: alice, target_account: bob) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a string' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Favourite' do
 | 
				
			||||||
 | 
					      let(:target) { Fabricate(:favourite, account: bob, status: status) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a string' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#url_for' do
 | 
				
			||||||
 | 
					    let(:alice)  { Fabricate(:account, username: 'alice') }
 | 
				
			||||||
 | 
					    let(:bob)    { Fabricate(:account, username: 'bob') }
 | 
				
			||||||
 | 
					    let(:status) { Fabricate(:status, text: 'Hello world', account: alice) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subject { TagManager.instance.url_for(target) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Account' do
 | 
				
			||||||
 | 
					      let(:target) { alice }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a URL' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Status' do
 | 
				
			||||||
 | 
					      let(:target) { status }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a URL' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Follow' do
 | 
				
			||||||
 | 
					      let(:target) { Fabricate(:follow, account: alice, target_account: bob) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a URL' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'Favourite' do
 | 
				
			||||||
 | 
					      let(:target) { Fabricate(:favourite, account: bob, status: status) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns a URL' do
 | 
				
			||||||
 | 
					        expect(subject).to be_a String
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -112,6 +112,10 @@ RSpec.describe Account, type: :model do
 | 
				
			|||||||
    pending
 | 
					    pending
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '.find_remote' do
 | 
				
			||||||
 | 
					    pending
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe 'MENTION_RE' do
 | 
					  describe 'MENTION_RE' do
 | 
				
			||||||
    subject { Account::MENTION_RE }
 | 
					    subject { Account::MENTION_RE }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe MediaAttachment, type: :model do
 | 
					RSpec.describe MediaAttachment, type: :model do
 | 
				
			||||||
  pending "add some examples to (or delete) #{__FILE__}"
 | 
					
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user