about summary refs log tree commit diff
path: root/app/services
diff options
context:
space:
mode:
Diffstat (limited to 'app/services')
-rw-r--r--app/services/block_service.rb18
-rw-r--r--app/services/fan_out_on_write_service.rb7
-rw-r--r--app/services/favourite_service.rb2
-rw-r--r--app/services/follow_remote_account_service.rb3
-rw-r--r--app/services/follow_service.rb4
-rw-r--r--app/services/notify_service.rb2
-rw-r--r--app/services/post_status_service.rb13
-rw-r--r--app/services/process_feed_service.rb2
-rw-r--r--app/services/process_hashtags_service.rb2
-rw-r--r--app/services/process_interaction_service.rb4
-rw-r--r--app/services/pubsubhubbub/subscribe_service.rb13
-rw-r--r--app/services/pubsubhubbub/unsubscribe_service.rb15
-rw-r--r--app/services/reblog_service.rb2
-rw-r--r--app/services/remove_status_service.rb5
-rw-r--r--app/services/search_service.rb6
-rw-r--r--app/services/unfollow_service.rb3
-rw-r--r--app/services/update_remote_profile_service.rb26
17 files changed, 91 insertions, 36 deletions
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index 388a592e0..6a032a5a1 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -6,19 +6,27 @@ class BlockService < BaseService
 
     UnfollowService.new.call(account, target_account) if account.following?(target_account)
     account.block!(target_account)
-    clear_mentions(account, target_account)
+    clear_timelines(account, target_account)
+    clear_notifications(account, target_account)
   end
 
   private
 
-  def clear_mentions(account, target_account)
-    timeline_key = FeedManager.instance.key(:mentions, account.id)
+  def clear_timelines(account, target_account)
+    mentions_key = FeedManager.instance.key(:mentions, account.id)
+    home_key     = FeedManager.instance.key(:home, account.id)
 
     target_account.statuses.select('id').find_each do |status|
-      redis.zrem(timeline_key, status.id)
+      redis.zrem(mentions_key, status.id)
+      redis.zrem(home_key, status.id)
     end
+  end
 
-    FeedManager.instance.broadcast(account.id, type: 'block', id: target_account.id)
+  def clear_notifications(account, target_account)
+    Notification.where(account: account).joins(:follow).where(activity_type: 'Follow', follows: { account_id: target_account.id }).destroy_all
+    Notification.where(account: account).joins(mention: :status).where(activity_type: 'Mention', statuses: { account_id: target_account.id }).destroy_all
+    Notification.where(account: account).joins(:favourite).where(activity_type: 'Favourite', favourites: { account_id: target_account.id }).destroy_all
+    Notification.where(account: account).joins(:status).where(activity_type: 'Status', statuses: { account_id: target_account.id }).destroy_all
   end
 
   def redis
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index 78cb0b13f..40d8a0fee 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -24,7 +24,7 @@ class FanOutOnWriteService < BaseService
   def deliver_to_followers(status)
     Rails.logger.debug "Delivering status #{status.id} to followers"
 
-    status.account.followers.where(domain: nil).find_each do |follower|
+    status.account.followers.where(domain: nil).joins(:user).where('users.current_sign_in_at > ?', 14.days.ago).find_each do |follower|
       next if FeedManager.instance.filter?(:home, status, follower)
       FeedManager.instance.push(:home, follower, status)
     end
@@ -41,14 +41,17 @@ class FanOutOnWriteService < BaseService
   end
 
   def deliver_to_hashtags(status)
-    Rails.logger.debug "Delivering status #{status.id} to hashtags"
+    return if status.reblog? || status.reply?
 
+    Rails.logger.debug "Delivering status #{status.id} to hashtags"
     status.tags.find_each do |tag|
       FeedManager.instance.broadcast("hashtag:#{tag.name}", type: 'update', id: status.id)
     end
   end
 
   def deliver_to_public(status)
+    return if status.reblog? || status.reply?
+
     Rails.logger.debug "Delivering status #{status.id} to public timeline"
     FeedManager.instance.broadcast(:public, type: 'update', id: status.id)
   end
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index 781b03b40..2f280e03f 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -7,7 +7,9 @@ class FavouriteService < BaseService
   # @return [Favourite]
   def call(account, status)
     favourite = Favourite.create!(account: account, status: status)
+
     HubPingWorker.perform_async(account.id)
+    Pubsubhubbub::DistributionWorker.perform_async(favourite.stream_entry.id)
 
     if status.local?
       NotifyService.new.call(status.account, favourite)
diff --git a/app/services/follow_remote_account_service.rb b/app/services/follow_remote_account_service.rb
index 37339d8ed..f640222b0 100644
--- a/app/services/follow_remote_account_service.rb
+++ b/app/services/follow_remote_account_service.rb
@@ -80,8 +80,7 @@ class FollowRemoteAccountService < BaseService
   end
 
   def get_profile(xml, account)
-    author = xml.at_xpath('/xmlns:feed/xmlns:author') || xml.at_xpath('/xmlns:feed').at_xpath('./dfrn:owner', dfrn: DFRN_NS)
-    update_remote_profile_service.call(author, account)
+    update_remote_profile_service.call(xml.at_xpath('/xmlns:feed'), account)
   end
 
   def update_remote_profile_service
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index cdae254bf..09fa295e3 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -19,7 +19,10 @@ class FollowService < BaseService
     end
 
     merge_into_timeline(target_account, source_account)
+
     HubPingWorker.perform_async(source_account.id)
+    Pubsubhubbub::DistributionWorker.perform_async(follow.stream_entry.id)
+
     follow
   end
 
@@ -33,7 +36,6 @@ class FollowService < BaseService
     end
 
     FeedManager.instance.trim(:home, into_account.id)
-    FeedManager.instance.broadcast(into_account.id, type: 'merge')
   end
 
   def redis
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index 772adfb90..1efd326b0 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -36,6 +36,8 @@ class NotifyService < BaseService
     blocked   = false
     blocked ||= @recipient.id == @notification.from_account.id
     blocked ||= @recipient.blocking?(@notification.from_account)
+    blocked ||= (@recipient.user.settings(:interactions).must_be_follower  && !@notification.from_account.following?(@recipient))
+    blocked ||= (@recipient.user.settings(:interactions).must_be_following && !@recipient.following?(@notification.from_account))
     blocked ||= send("blocked_#{@notification.type}?")
     blocked
   end
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index cf824ff99..979a157e9 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -5,15 +5,20 @@ class PostStatusService < BaseService
   # @param [Account] account Account from which to post
   # @param [String] text Message
   # @param [Status] in_reply_to Optional status to reply to
-  # @param [Enumerable] media_ids Optional array of media IDs to attach
+  # @param [Hash] options
+  # @option [Boolean] :sensitive
+  # @option [Enumerable] :media_ids Optional array of media IDs to attach
   # @return [Status]
-  def call(account, text, in_reply_to = nil, media_ids = nil)
-    status = account.statuses.create!(text: text, thread: in_reply_to)
-    attach_media(status, media_ids)
+  def call(account, text, in_reply_to = nil, options = {})
+    status = account.statuses.create!(text: text, thread: in_reply_to, sensitive: options[:sensitive])
+    attach_media(status, options[:media_ids])
     process_mentions_service.call(status)
     process_hashtags_service.call(status)
+
     DistributionWorker.perform_async(status.id)
     HubPingWorker.perform_async(account.id)
+    Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id)
+
     status
   end
 
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
index 1cd801b80..a7a4cb2b0 100644
--- a/app/services/process_feed_service.rb
+++ b/app/services/process_feed_service.rb
@@ -16,7 +16,7 @@ class ProcessFeedService < BaseService
 
   def update_author(xml, account)
     return if xml.at_xpath('/xmlns:feed').nil?
-    UpdateRemoteProfileService.new.call(xml.at_xpath('/xmlns:feed/xmlns:author'), account)
+    UpdateRemoteProfileService.new.call(xml.at_xpath('/xmlns:feed'), account, true)
   end
 
   def process_entries(xml, account)
diff --git a/app/services/process_hashtags_service.rb b/app/services/process_hashtags_service.rb
index 3bf3471ec..fa14c44da 100644
--- a/app/services/process_hashtags_service.rb
+++ b/app/services/process_hashtags_service.rb
@@ -4,7 +4,7 @@ class ProcessHashtagsService < BaseService
   def call(status, tags = [])
     tags = status.text.scan(Tag::HASHTAG_RE).map(&:first) if status.local?
 
-    tags.map(&:downcase).uniq.each do |tag|
+    tags.map { |str| str.mb_chars.downcase }.uniq.each do |tag|
       status.tags << Tag.where(name: tag).first_or_initialize(name: tag)
     end
   end
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
index e7bb3c73b..6b2f6e2d2 100644
--- a/app/services/process_interaction_service.rb
+++ b/app/services/process_interaction_service.rb
@@ -26,7 +26,7 @@ class ProcessInteractionService < BaseService
     end
 
     if salmon.verify(envelope, account.keypair)
-      update_remote_profile_service.call(xml.at_xpath('/xmlns:entry/xmlns:author'), account)
+      update_remote_profile_service.call(xml.at_xpath('/xmlns:entry'), account, true)
 
       case verb(xml)
       when :follow
@@ -74,7 +74,7 @@ class ProcessInteractionService < BaseService
   end
 
   def delete_post!(xml, account)
-    status = Status.find(activity_id(xml))
+    status = Status.find(xml.at_xpath('//xmlns:id').content)
 
     return if status.nil?
 
diff --git a/app/services/pubsubhubbub/subscribe_service.rb b/app/services/pubsubhubbub/subscribe_service.rb
new file mode 100644
index 000000000..343376d77
--- /dev/null
+++ b/app/services/pubsubhubbub/subscribe_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class Pubsubhubbub::SubscribeService < BaseService
+  def call(account, callback, secret, lease_seconds)
+    return ['Invalid topic URL', 422] if account.nil?
+    return ['Invalid callback URL', 422] unless !callback.blank? && callback =~ /\A#{URI.regexp(%w(http https))}\z/
+
+    subscription = Subscription.where(account: account, callback_url: callback).first_or_create!(account: account, callback_url: callback)
+    Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds)
+
+    ['', 202]
+  end
+end
diff --git a/app/services/pubsubhubbub/unsubscribe_service.rb b/app/services/pubsubhubbub/unsubscribe_service.rb
new file mode 100644
index 000000000..62459a0aa
--- /dev/null
+++ b/app/services/pubsubhubbub/unsubscribe_service.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class Pubsubhubbub::UnsubscribeService < BaseService
+  def call(account, callback)
+    return ['Invalid topic URL', 422] if account.nil?
+
+    subscription = Subscription.where(account: account, callback_url: callback)
+
+    unless subscription.nil?
+      Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'unsubscribe')
+    end
+
+    ['', 202]
+  end
+end
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 6543d4ae7..39fdb4ea7 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -7,8 +7,10 @@ class ReblogService < BaseService
   # @return [Status]
   def call(account, reblogged_status)
     reblog = account.statuses.create!(reblog: reblogged_status, text: '')
+
     DistributionWorker.perform_async(reblog.id)
     HubPingWorker.perform_async(account.id)
+    Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
 
     if reblogged_status.local?
       NotifyService.new.call(reblogged_status.account, reblog)
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 689abc97b..4e03661da 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -10,6 +10,11 @@ class RemoveStatusService < BaseService
     remove_from_public(status)
 
     status.destroy!
+
+    if status.account.local?
+      HubPingWorker.perform_async(status.account.id)
+      Pubsubhubbub::DistributionWorker.perform_async(status.stream_entry.id)
+    end
   end
 
   private
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index c4cffda13..1ae1d5a80 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -2,9 +2,9 @@
 
 class SearchService < BaseService
   def call(query, limit, resolve = false)
-    return if query.blank?
+    return if query.blank? || query.start_with?('#')
 
-    username, domain = query.split('@')
+    username, domain = query.gsub(/\A@/, '').split('@')
 
     results = if domain.nil?
                 Account.search_for(username)
@@ -12,7 +12,7 @@ class SearchService < BaseService
                 Account.search_for("#{username} #{domain}")
               end
 
-    results = results.limit(limit).with_counters
+    results = results.limit(limit)
 
     if resolve && results.empty? && !domain.nil?
       results = [FollowRemoteAccountService.new.call("#{username}@#{domain}")]
diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb
index b3386a99c..7973a3611 100644
--- a/app/services/unfollow_service.rb
+++ b/app/services/unfollow_service.rb
@@ -17,9 +17,8 @@ class UnfollowService < BaseService
 
     from_account.statuses.select('id').find_each do |status|
       redis.zrem(timeline_key, status.id)
+      redis.zremrangebyscore(timeline_key, status.id, status.id)
     end
-
-    FeedManager.instance.broadcast(into_account.id, type: 'unmerge')
   end
 
   def redis
diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb
index 2909ae12a..56b25816f 100644
--- a/app/services/update_remote_profile_service.rb
+++ b/app/services/update_remote_profile_service.rb
@@ -2,24 +2,24 @@
 
 class UpdateRemoteProfileService < BaseService
   POCO_NS = 'http://portablecontacts.net/spec/1.0'
+  DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'
 
-  def call(author_xml, account)
-    return if author_xml.nil?
+  def call(xml, account, resubscribe = false)
+    return if xml.nil?
 
-    account.display_name = if author_xml.at_xpath('./poco:displayName', poco: POCO_NS).nil?
-                             account.username
-                           else
-                             author_xml.at_xpath('./poco:displayName', poco: POCO_NS).content
-                           end
+    author_xml = xml.at_xpath('./xmlns:author') || xml.at_xpath('./dfrn:owner', dfrn: DFRN_NS)
+    hub_link   = xml.at_xpath('./xmlns:link[@rel="hub"]')
 
-    unless author_xml.at_xpath('./poco:note').nil?
-      account.note = author_xml.at_xpath('./poco:note', poco: POCO_NS).content
-    end
-
-    unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]').nil?
-      account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]').attribute('href').value
+    unless author_xml.nil?
+      account.display_name      = author_xml.at_xpath('./poco:displayName', poco: POCO_NS).content unless author_xml.at_xpath('./poco:displayName', poco: POCO_NS).nil?
+      account.note              = author_xml.at_xpath('./poco:note', poco: POCO_NS).content unless author_xml.at_xpath('./poco:note').nil?
+      account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]')['href'] unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]').nil? || author_xml.at_xpath('./xmlns:link[@rel="avatar"]')['href'].blank?
     end
 
+    old_hub_url     = account.hub_url
+    account.hub_url = hub_link['href'] if !hub_link.nil? && !hub_link['href'].blank? && (hub_link['href'] != old_hub_url)
     account.save!
+
+    SubscribeService.new.call(account) if resubscribe && (account.hub_url != old_hub_url)
   end
 end