From 7b2ba61c4841e23081552fb79270e4e430dd1fe0 Mon Sep 17 00:00:00 2001 From: noellabo Date: Sat, 5 Sep 2020 16:03:52 +0900 Subject: [PATCH] Add the ability to change to a new circle by replying to a circle --- .../mastodon/components/status_action_bar.js | 2 +- .../features/status/components/action_bar.js | 2 +- app/models/status.rb | 23 ++++++++++++++++--- app/policies/status_policy.rb | 2 +- app/serializers/rest/status_serializer.rb | 6 ++--- app/services/post_status_service.rb | 6 +---- app/services/process_mentions_service.rb | 4 +--- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index 1234a846d3197e..d854b39b448b6c 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -256,7 +256,7 @@ class StatusActionBar extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark), action: this.handleBookmarkClick }); menu.push(null); - if (status.getIn(['account', 'id']) === me && status.get('visibility') === 'limited' && !status.get('in_reply_to_id')) { + if (status.getIn(['account', 'id']) === me && status.get('visibility') === 'limited' && status.get('circle_id')) { menu.push({ text: intl.formatMessage(messages.showMemberList), action: this.handleMemberListClick }); menu.push(null); } diff --git a/app/javascript/mastodon/features/status/components/action_bar.js b/app/javascript/mastodon/features/status/components/action_bar.js index d2cf586658cec5..a30c77fd353422 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.js +++ b/app/javascript/mastodon/features/status/components/action_bar.js @@ -210,7 +210,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); } - if (status.get('visibility') === 'limited' && !status.get('in_reply_to_id')) { + if (status.get('visibility') === 'limited' && status.get('circle_id')) { menu.push({ text: intl.formatMessage(messages.showMemberList), action: this.handleMemberListClick }); } diff --git a/app/models/status.rb b/app/models/status.rb index 28ae80e09024f9..bdfa36e7d7f485 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -33,6 +33,7 @@ class Status < ApplicationRecord include Cacheable include StatusThreadingConcern include RateLimitable + include Redisable rate_limit by: :account, family: :statuses @@ -42,6 +43,8 @@ class Status < ApplicationRecord # will be based on current time instead of `created_at` attr_accessor :override_timestamps + attr_accessor :circle + update_index('statuses#status', :proper) enum visibility: [:public, :unlisted, :private, :direct, :limited], _suffix: :visibility @@ -276,6 +279,7 @@ def decrement_count!(key) before_validation :set_local, on: :create after_create :set_poll_id + after_create :set_circle class << self def selectable_visibilities @@ -467,10 +471,23 @@ def set_conversation if reply? && !thread.nil? self.in_reply_to_account_id = carried_over_reply_to_account_id - self.conversation_id = thread.conversation_id if conversation_id.nil? - elsif conversation_id.nil? - build_owned_conversation end + + if conversation_id.nil? + if reply? && !thread.nil? && circle.nil? + self.conversation_id = thread.conversation_id + else + build_owned_conversation + end + end + end + + def set_circle + redis.setex(circle_id_key, 3.days.seconds, circle.id) if circle.present? + end + + def circle_id_key + "statuses/#{id}/circle_id" end def carried_over_reply_to_account_id diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 71276f842efb70..fde31de3455898 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -42,7 +42,7 @@ def update? end def show_mentions? - limited? && !reply? && owned? + limited? && owned? && (!reply? || record.thread.conversation_id != record.conversation_id) end private diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb index 7d6a5e55b669a6..4ccc5deb624484 100644 --- a/app/serializers/rest/status_serializer.rb +++ b/app/serializers/rest/status_serializer.rb @@ -11,7 +11,7 @@ class REST::StatusSerializer < ActiveModel::Serializer attribute :muted, if: :current_user? attribute :bookmarked, if: :current_user? attribute :pinned, if: :pinnable? - attribute :circle_id, if: :limited_owned_status? + attribute :circle_id, if: :limited_owned_parent_status? attribute :content, unless: :source_requested? attribute :text, if: :source_requested? @@ -67,8 +67,8 @@ def limited object.limited_visibility? end - def limited_owned_status? - object.limited_visibility? && owned_status? && object.in_reply_to_id.nil? + def limited_owned_parent_status? + object.limited_visibility? && owned_status? && (!object.reply? || object.thread.conversation_id != object.conversation_id) end def circle_id diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index 45606b3f05c95a..552772fbc8b055 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -73,7 +73,6 @@ def process_status! ProcessHashtagsService.new.call(@status) ProcessMentionsService.new.call(@status, @circle) - redis.setex(circle_id_key, 3.days.seconds, @circle.id) if @circle.present? end def schedule_status! @@ -119,10 +118,6 @@ def scheduled? @scheduled_at.present? end - def circle_id_key - "statuses/#{@status.id}/circle_id" - end - def idempotency_key "idempotency:status:#{@account.id}:#{@options[:idempotency]}" end @@ -163,6 +158,7 @@ def status_attributes sensitive: @sensitive, spoiler_text: @options[:spoiler_text] || '', visibility: @visibility, + circle: @circle, language: language_from_option(@options[:language]) || @account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(@text, @account), application: @options[:application], rate_limit: @options[:with_rate_limit], diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index dea4a33f35dbde..19b4f28c32dc95 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -47,9 +47,7 @@ def call(status, circle = nil) circle.accounts.find_each do |target_account| status.mentions.create(silent: true, account: target_account) end - end - - if status.limited_visibility? && status.thread&.limited_visibility? + elsif status.limited_visibility? && status.thread&.limited_visibility? # If we are replying to a local status, then we'll have the complete # audience copied here, both local and remote. If we are replying # to a remote status, only local audience will be copied. Then we