Add option to be notified when a followed user posts (#13546)

* Add bell button

Fix #4890

* Remove duplicate type from post-deployment migration

* Fix legacy class type mappings

* Improve query performance with better index

* Fix validation

* Remove redundant index from notifications
This commit is contained in:
Eugen Rochko 2020-09-18 17:26:45 +02:00 committed by GitHub
parent 75e4bd9413
commit 974b1b79ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 330 additions and 112 deletions

View file

@ -8,6 +8,7 @@ module AccountInteractions
Follow.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow, mapping|
mapping[follow.target_account_id] = {
reblogs: follow.show_reblogs?,
notify: follow.notify?,
}
end
end
@ -36,6 +37,7 @@ module AccountInteractions
FollowRequest.where(target_account_id: target_account_ids, account_id: account_id).each_with_object({}) do |follow_request, mapping|
mapping[follow_request.target_account_id] = {
reblogs: follow_request.show_reblogs?,
notify: follow_request.notify?,
}
end
end
@ -95,25 +97,29 @@ module AccountInteractions
has_many :announcement_mutes, dependent: :destroy
end
def follow!(other_account, reblogs: nil, uri: nil, rate_limit: false)
reblogs = true if reblogs.nil?
rel = active_relationships.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit)
def follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false)
rel = active_relationships.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit)
.find_or_create_by!(target_account: other_account)
rel.update!(show_reblogs: reblogs)
rel.show_reblogs = reblogs unless reblogs.nil?
rel.notify = notify unless notify.nil?
rel.save! if rel.changed?
remove_potential_friendship(other_account)
rel
end
def request_follow!(other_account, reblogs: nil, uri: nil, rate_limit: false)
reblogs = true if reblogs.nil?
rel = follow_requests.create_with(show_reblogs: reblogs, uri: uri, rate_limit: rate_limit)
def request_follow!(other_account, reblogs: nil, notify: nil, uri: nil, rate_limit: false)
rel = follow_requests.create_with(show_reblogs: reblogs.nil? ? true : reblogs, notify: notify.nil? ? false : notify, uri: uri, rate_limit: rate_limit)
.find_or_create_by!(target_account: other_account)
rel.update!(show_reblogs: reblogs)
rel.show_reblogs = reblogs unless reblogs.nil?
rel.notify = notify unless notify.nil?
rel.save! if rel.changed?
remove_potential_friendship(other_account)
rel

View file

@ -10,6 +10,7 @@
# target_account_id :bigint(8) not null
# show_reblogs :boolean default(TRUE), not null
# uri :string
# notify :boolean default(FALSE), not null
#
class Follow < ApplicationRecord
@ -34,7 +35,7 @@ class Follow < ApplicationRecord
end
def revoke_request!
FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, uri: uri)
FollowRequest.create!(account: account, target_account: target_account, show_reblogs: show_reblogs, notify: notify, uri: uri)
destroy!
end

View file

@ -10,6 +10,7 @@
# target_account_id :bigint(8) not null
# show_reblogs :boolean default(TRUE), not null
# uri :string
# notify :boolean default(FALSE), not null
#
class FollowRequest < ApplicationRecord
@ -28,7 +29,7 @@ class FollowRequest < ApplicationRecord
validates_with FollowLimitValidator, on: :create
def authorize!
account.follow!(target_account, reblogs: show_reblogs, uri: uri)
account.follow!(target_account, reblogs: show_reblogs, notify: notify, uri: uri)
MergeWorker.perform_async(target_account.id, account.id) if account.local?
destroy!
end

View file

@ -10,21 +10,34 @@
# updated_at :datetime not null
# account_id :bigint(8) not null
# from_account_id :bigint(8) not null
# type :string
#
class Notification < ApplicationRecord
self.inheritance_column = nil
include Paginable
include Cacheable
TYPE_CLASS_MAP = {
mention: 'Mention',
reblog: 'Status',
follow: 'Follow',
follow_request: 'FollowRequest',
favourite: 'Favourite',
poll: 'Poll',
LEGACY_TYPE_CLASS_MAP = {
'Mention' => :mention,
'Status' => :reblog,
'Follow' => :follow,
'FollowRequest' => :follow_request,
'Favourite' => :favourite,
'Poll' => :poll,
}.freeze
TYPES = %i(
mention
status
reblog
follow
follow_request
favourite
poll
).freeze
STATUS_INCLUDES = [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account]].freeze
belongs_to :account, optional: true
@ -38,29 +51,30 @@ class Notification < ApplicationRecord
belongs_to :favourite, foreign_type: 'Favourite', foreign_key: 'activity_id', optional: true
belongs_to :poll, foreign_type: 'Poll', foreign_key: 'activity_id', optional: true
validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
validates :type, inclusion: { in: TYPES }
scope :without_suspended, -> { joins(:from_account).merge(Account.without_suspended) }
scope :browserable, ->(exclude_types = [], account_id = nil) {
types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types)
types = TYPES - exclude_types.map(&:to_sym)
if account_id.nil?
where(activity_type: types)
where(type: types)
else
where(activity_type: types, from_account_id: account_id)
where(type: types, from_account_id: account_id)
end
}
cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, follow_request: :account, poll: [status: STATUS_INCLUDES]
def type
@type ||= TYPE_CLASS_MAP.invert[activity_type].to_sym
@type ||= (super || LEGACY_TYPE_CLASS_MAP[activity_type]).to_sym
end
def target_status
case type
when :status
status
when :reblog
status&.reblog
when :favourite
@ -89,10 +103,6 @@ class Notification < ApplicationRecord
item.target_status.account = accounts[item.target_status.account_id] if item.target_status
end
end
def activity_types_from_types(types)
types.map { |type| TYPE_CLASS_MAP[type.to_sym] }.compact
end
end
after_initialize :set_from_account