From a08e724476f47b85de9bb334eeadaf882a7a23ee Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 25 Mar 2016 02:13:30 +0100 Subject: Fix subscriptions:clear task, refactor feeds, refactor streamable activites and atom feed generation to some extent, as well as the way mentions are stored --- app/models/account.rb | 18 ++++++------------ app/models/concerns/streamable.rb | 31 +++++++++++++++++++++++++++++++ app/models/concerns/targetable.rb | 9 +++++++++ app/models/favourite.rb | 22 +++++----------------- app/models/feed.rb | 15 +++++++++------ app/models/follow.rb | 20 ++++---------------- app/models/status.rb | 27 +++++++++------------------ app/models/stream_entry.rb | 2 +- 8 files changed, 74 insertions(+), 70 deletions(-) create mode 100644 app/models/concerns/streamable.rb create mode 100644 app/models/concerns/targetable.rb (limited to 'app/models') diff --git a/app/models/account.rb b/app/models/account.rb index c686a47ed..007fc77b6 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -1,4 +1,6 @@ class Account < ActiveRecord::Base + include Targetable + # Local users has_one :user, inverse_of: :account validates :username, uniqueness: { scope: :domain, case_sensitive: false }, if: 'local?' @@ -52,18 +54,6 @@ class Account < ActiveRecord::Base local? ? self.username : "#{self.username}@#{self.domain}" end - def object_type - :person - end - - def title - self.username - end - - def content - self.note - end - def subscribed? !(self.secret.blank? || self.verify_token.blank?) end @@ -97,6 +87,10 @@ class Account < ActiveRecord::Base self[:avatar_remote_url] = url end + def object_type + :person + end + def to_param self.username end diff --git a/app/models/concerns/streamable.rb b/app/models/concerns/streamable.rb new file mode 100644 index 000000000..9f7c6e4a3 --- /dev/null +++ b/app/models/concerns/streamable.rb @@ -0,0 +1,31 @@ +module Streamable + extend ActiveSupport::Concern + + included do + has_one :stream_entry, as: :activity + + def title + super + end + + def content + title + end + + def target + super + end + + def object_type + :activity + end + + def thread + super + end + + after_create do + self.account.stream_entries.create!(activity: self) + end + end +end diff --git a/app/models/concerns/targetable.rb b/app/models/concerns/targetable.rb new file mode 100644 index 000000000..d46590a02 --- /dev/null +++ b/app/models/concerns/targetable.rb @@ -0,0 +1,9 @@ +module Targetable + extend ActiveSupport::Concern + + included do + def object_type + :object + end + end +end diff --git a/app/models/favourite.rb b/app/models/favourite.rb index 20260f46b..46310a5ff 100644 --- a/app/models/favourite.rb +++ b/app/models/favourite.rb @@ -1,9 +1,9 @@ class Favourite < ActiveRecord::Base + include Streamable + belongs_to :account, inverse_of: :favourites belongs_to :status, inverse_of: :favourites - has_one :stream_entry, as: :activity - def verb :favorite end @@ -12,27 +12,15 @@ class Favourite < ActiveRecord::Base "#{self.account.acct} favourited a status by #{self.status.account.acct}" end - def content - title - end - def object_type target.object_type end - def target - self.status - end - - def mentions - [] - end - def thread - target + self.status end - after_create do - self.account.stream_entries.create!(activity: self) + def target + thread end end diff --git a/app/models/feed.rb b/app/models/feed.rb index 206f287e7..1d6c2cfbf 100644 --- a/app/models/feed.rb +++ b/app/models/feed.rb @@ -4,21 +4,24 @@ class Feed @account = account end - def get(limit, max_id = '+inf') + def get(limit, max_id) + max_id = '+inf' if max_id.nil? unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", '-inf', limit: [0, limit]) status_map = Hash.new # If we're after most recent items and none are there, we need to precompute the feed - return PrecomputeFeedService.new.(@type, @account).take(limit) if unhydrated.empty? && max_id == '+inf' - - Status.where(id: unhydrated).with_includes.with_counters.each { |status| status_map[status.id.to_s] = status } - return unhydrated.map { |id| status_map[id] }.compact + if unhydrated.empty? && max_id == '+inf' + PrecomputeFeedService.new.(@type, @account, limit) + else + Status.where(id: unhydrated).with_includes.with_counters.each { |status| status_map[status.id.to_s] = status } + unhydrated.map { |id| status_map[id] }.compact + end end private def key - "feed:#{@type}:#{@account.id}" + FeedManager.key(@type, @account.id) end def redis diff --git a/app/models/follow.rb b/app/models/follow.rb index e458a07f3..94263b1a7 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -1,9 +1,9 @@ class Follow < ActiveRecord::Base + include Streamable + belongs_to :account belongs_to :target_account, class_name: 'Account' - has_one :stream_entry, as: :activity - validates :account, :target_account, presence: true validates :account_id, uniqueness: { scope: :target_account_id } @@ -16,22 +16,10 @@ class Follow < ActiveRecord::Base end def object_type - target.object_type - end - - def content - self.destroyed? ? "#{self.account.acct} is no longer following #{self.target_account.acct}" : "#{self.account.acct} started following #{self.target_account.acct}" + :person end def title - content - end - - def mentions - [] - end - - after_create do - self.account.stream_entries.create!(activity: self) + self.destroyed? ? "#{self.account.acct} is no longer following #{self.target_account.acct}" : "#{self.account.acct} started following #{self.target_account.acct}" end end diff --git a/app/models/status.rb b/app/models/status.rb index 76218bea0..59c94aaca 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -1,24 +1,23 @@ class Status < ActiveRecord::Base include Paginable + include Streamable belongs_to :account, inverse_of: :statuses belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs - has_one :stream_entry, as: :activity - has_many :favourites, inverse_of: :status, dependent: :destroy has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread - has_many :mentioned_accounts, class_name: 'Mention', dependent: :destroy + has_many :mentions, dependent: :destroy validates :account, presence: true validates :uri, uniqueness: true, unless: 'local?' validates :text, presence: true, if: Proc.new { |s| s.local? && !s.reblog? } scope :with_counters, -> { select('statuses.*, (select count(r.id) from statuses as r where r.reblog_of_id = statuses.id) as reblogs_count, (select count(f.id) from favourites as f where f.status_id = statuses.id) as favourites_count') } - scope :with_includes, -> { includes(:account, :mentioned_accounts, reblog: [:account, :mentioned_accounts], thread: [:account, :mentioned_accounts]) } + scope :with_includes, -> { includes(:account, :mentions, reblog: [:account, :mentions], thread: [:account, :mentions]) } def local? self.uri.nil? @@ -60,18 +59,6 @@ class Status < ActiveRecord::Base self.attributes['favourites_count'] || self.favourites.count end - def mentions - if @mentions.nil? - @mentions = [] - @mentions << thread.account if reply? - @mentions << reblog.account if reblog? - self.mentioned_accounts.each { |mention| @mentions << mention.account } unless reblog? - @mentions = @mentions.uniq - end - - @mentions - end - def ancestors Status.where(id: Status.find_by_sql(['WITH RECURSIVE search_tree(id, in_reply_to_id, path) AS (SELECT id, in_reply_to_id, ARRAY[id] FROM statuses WHERE id = ? UNION ALL SELECT statuses.id, statuses.in_reply_to_id, path || statuses.id FROM search_tree JOIN statuses ON statuses.id = search_tree.in_reply_to_id WHERE NOT statuses.id = ANY(path)) SELECT id FROM search_tree ORDER BY path DESC', self.id]) - [self]) end @@ -80,7 +67,11 @@ class Status < ActiveRecord::Base Status.where(id: Status.find_by_sql(['WITH RECURSIVE search_tree(id, path) AS (SELECT id, ARRAY[id] FROM statuses WHERE id = ? UNION ALL SELECT statuses.id, path || statuses.id FROM search_tree JOIN statuses ON statuses.in_reply_to_id = search_tree.id WHERE NOT statuses.id = ANY(path)) SELECT id FROM search_tree ORDER BY path', self.id]) - [self]) end - after_create do - self.account.stream_entries.create!(activity: self) + def self.as_home_timeline(account) + self.where(account: [account] + account.following).with_includes.with_counters + end + + def self.as_mentions_timeline(account) + self.where(id: Mention.where(account: account).pluck(:status_id)).with_includes.with_counters end end diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb index 35eab1df0..2972d94f6 100644 --- a/app/models/stream_entry.rb +++ b/app/models/stream_entry.rb @@ -41,7 +41,7 @@ class StreamEntry < ActiveRecord::Base end def mentions - orphaned? ? [] : self.activity.mentions + self.activity.respond_to?(:mentions) ? self.activity.mentions.map { |x| x.account } : [] end private -- cgit