about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFire Demon <firedemon@creature.cafe>2020-08-14 02:41:44 -0500
committerFire Demon <firedemon@creature.cafe>2020-08-30 05:45:18 -0500
commitabfd0c107c8003ba06a118625c49d22df553696f (patch)
treebb41e6b47b2848233b7830b179a7b2e4df21dd91
parentd97a574b07cb60e9c2bdd98ace5049e73ee9b861 (diff)
[Command Tags] Add #!notify toggle to allow toggling whether or not a post should be locally delivered to timelines/notifications
-rw-r--r--app/javascript/flavours/glitch/components/status_content.js12
-rw-r--r--app/lib/command_tag/command/status_tools.rb8
-rw-r--r--app/models/status.rb14
-rw-r--r--app/serializers/rest/status_serializer.rb1
-rw-r--r--app/services/fan_out_on_write_service.rb2
-rw-r--r--app/services/post_status_service.rb3
-rw-r--r--app/services/process_mentions_service.rb2
-rw-r--r--app/services/update_status_service.rb2
-rw-r--r--app/workers/distribution_worker.rb2
9 files changed, 43 insertions, 3 deletions
diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js
index f03072ac8..0b3f3048b 100644
--- a/app/javascript/flavours/glitch/components/status_content.js
+++ b/app/javascript/flavours/glitch/components/status_content.js
@@ -313,9 +313,21 @@ export default class StatusContent extends React.PureComponent {
       </div>
     );
 
+    const quiet = (status.get('notify') === false) && (
+      <div className='status__notice status__quiet-notice'>
+        <Icon id='bell-slash' />
+        <FormattedMessage
+          id='status.quiet'
+          defaultMessage='Quiet local publish'
+          key={`quiet-${status.get('id')}`}
+        />
+      </div>
+    );
+
     const status_notice_wrapper = (
       <div className='status__notice-wrapper'>
         {unpublished}
+        {quiet}
         {edited}
         {local_only}
       </div>
diff --git a/app/lib/command_tag/command/status_tools.rb b/app/lib/command_tag/command/status_tools.rb
index daa44601b..a323138ea 100644
--- a/app/lib/command_tag/command/status_tools.rb
+++ b/app/lib/command_tag/command/status_tools.rb
@@ -41,6 +41,14 @@ module CommandTag::Command::StatusTools
   alias handle_p_before_save                      handle_visibility_before_save
   alias handle_privacy_before_save                handle_visibility_before_save
 
+  def handle_notify_before_save(args)
+    return if args[0].blank?
+
+    @status.notify = read_boolean_from(args[0])
+  end
+
+  alias handle_notice_before_save handle_notify_before_save
+
   private
 
   def resolve_mention(mention_text)
diff --git a/app/models/status.rb b/app/models/status.rb
index e81331e93..c12e72f10 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -298,6 +298,20 @@ class Status < ApplicationRecord
     update_status_stat!(key => [public_send(key) - 1, 0].max)
   end
 
+  def notify=(value)
+    Redis.current.set("status:#{id}:notify", value ? 1 : 0, ex: 1.hour)
+    @notify = value
+  end
+
+  def notify
+    return @notify if defined?(@notify)
+
+    value = Redis.current.get("status:#{id}:notify")
+    @notify = value.nil? ? true : value.to_i == 1
+  end
+
+  alias notify? notify
+
   def less_private_than?(other_visibility)
     return false if other_visibility.blank?
 
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index 96ae59c62..8578775c4 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -23,6 +23,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
   attribute :published if :local?
   attribute :hidden, if: :current_user?
   attribute :conversation_hidden, if: :current_user?
+  attribute :notify, if: :locally_owned?
 
   belongs_to :reblog, serializer: REST::StatusSerializer
   belongs_to :application, if: :show_application?
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index 6102ed1e5..1e12def33 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -92,7 +92,7 @@ class FanOutOnWriteService < BaseService
 
     Rails.logger.debug "Delivering status #{status.id} to public timeline"
 
-    Redis.current.set(key, true, ex: 6.hours)
+    Redis.current.set(key, 1, ex: 6.hours)
 
     Redis.current.publish('timeline:public', @payload)
     if status.local?
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 82588d254..c6a983001 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -27,6 +27,7 @@ class PostStatusService < BaseService
   # @option [Enumerable] :mentions Optional array of Mentions to include
   # @option [Enumerable] :tags Option array of tag names to include
   # @option [Boolean] :publish If true, status will be published
+  # @option [Boolean] :notify If false, status will not be delivered to local timelines or mentions
   # @return [Status]
   def call(account, options = {})
     @account     = account
@@ -91,6 +92,8 @@ class PostStatusService < BaseService
       @status = @account.statuses.create!(status_attributes)
     end
 
+    @status.notify = @options[:notify] if @options[:notify].present?
+
     process_command_tags_service.call(@account, @status)
     process_hashtags_service.call(@status, nil, @tag_names)
     process_mentions_service.call(@status, mentions: @mentions, deliver: @options[:publish])
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 3752cebb9..fea00ef4f 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -31,7 +31,7 @@ class ProcessMentionsService < BaseService
     mentioned_account = mention.account
 
     if mentioned_account.local?
-      LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name) unless mention.silent?
+      LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name) unless !@status.notify? || mention.silent?
     elsif mentioned_account.activitypub? && !@status.local_only?
       ActivityPub::DeliveryWorker.perform_async(activitypub_json(mentioned_account.domain), mention.status.account_id, mentioned_account.inbox_url)
     end
diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb
index 05586aa1b..327cc74ea 100644
--- a/app/services/update_status_service.rb
+++ b/app/services/update_status_service.rb
@@ -147,6 +147,8 @@ class UpdateStatusService < BaseService
 
     ActivityPub::DistributionWorker.perform_async(@status.id) if @status.local? && !@status.local_only?
 
+    return unless @status.notify?
+
     mentions = @status.active_mentions.includes(:account).where(id: @new_mention_ids, accounts: { domain: nil })
     mentions.each { |mention| LocalNotificationWorker.perform_async(mention.account.id, mention.id, mention.class.name) }
   end
diff --git a/app/workers/distribution_worker.rb b/app/workers/distribution_worker.rb
index 765cd76c8..049d2732b 100644
--- a/app/workers/distribution_worker.rb
+++ b/app/workers/distribution_worker.rb
@@ -7,7 +7,7 @@ class DistributionWorker
     RedisLock.acquire(redis: Redis.current, key: "distribute:#{status_id}") do |lock|
       if lock.acquired?
         status = Status.find(status_id)
-        FanOutOnWriteService.new.call(status, only_to_self: !status.published? || only_to_self)
+        FanOutOnWriteService.new.call(status, only_to_self: !status.published? || only_to_self || !status.notify?)
       else
         raise Mastodon::RaceConditionError
       end