From 79535cb863d2f956bff2af8449f10da4aede4ede Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Fri, 14 Aug 2020 14:09:33 -0500 Subject: [Feature] Add support for unlisted and out-of-body tags --- app/controllers/admin/tags_controller.rb | 2 +- app/lib/command_tag/command/status_tools.rb | 24 ++++++++++++++++++++++++ app/models/status.rb | 6 +++--- app/services/fan_out_on_write_service.rb | 7 ++----- app/services/process_hashtags_service.rb | 2 +- app/services/remove_hashtags_service.rb | 21 +++++++++++++++++++++ app/services/remove_status_service.rb | 6 +++--- app/services/revoke_status_service.rb | 10 +++++----- app/services/update_status_service.rb | 12 +++++------- 9 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 app/services/remove_hashtags_service.rb diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb index 59df4470e..8abe19626 100644 --- a/app/controllers/admin/tags_controller.rb +++ b/app/controllers/admin/tags_controller.rb @@ -54,7 +54,7 @@ module Admin def set_usage_by_domain @usage_by_domain = @tag.statuses - .with_public_visibility + .distributable .excluding_silenced_accounts .where(Status.arel_table[:id].gteq(Mastodon::Snowflake.id_at(Time.now.utc.beginning_of_day))) .joins(:account) diff --git a/app/lib/command_tag/command/status_tools.rb b/app/lib/command_tag/command/status_tools.rb index a323138ea..1727a956e 100644 --- a/app/lib/command_tag/command/status_tools.rb +++ b/app/lib/command_tag/command/status_tools.rb @@ -49,6 +49,30 @@ module CommandTag::Command::StatusTools alias handle_notice_before_save handle_notify_before_save + def handle_tags_before_save(args) + return if args.blank? + + cmd = args.shift.downcase + args.select! { |tag| tag =~ /\A(#{Tag::HASHTAG_NAME_RE})\z/i } + + case cmd + when 'add', 'a', '+' + ProcessHashtagsService.new.call(@status, args) + when 'del', 'remove', 'rm', 'r', 'd', '-' + RemoveHashtagsService.new.call(@status, args) + end + end + + def handle_tag_before_save(args) + args.unshift('add') + handle_tags_before_save(args) + end + + def handle_untag_before_save(args) + args.unshift('del') + handle_tags_before_save(args) + end + private def resolve_mention(mention_text) diff --git a/app/models/status.rb b/app/models/status.rb index c12e72f10..e568bfed7 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -447,7 +447,7 @@ class Status < ApplicationRecord end def as_tag_timeline(tag, account = nil, local_only = false) - query = timeline_scope(local_only).tagged_with(tag) + query = timeline_scope(local_only, include_unlisted: true).tagged_with(tag) apply_timeline_filters(query, account, local_only) end @@ -544,7 +544,7 @@ class Status < ApplicationRecord private - def timeline_scope(scope = false) + def timeline_scope(scope = false, include_unlisted: false) starting_scope = case scope when :local, true Status.local @@ -555,7 +555,7 @@ class Status < ApplicationRecord else Status end - starting_scope = starting_scope.with_public_visibility.published + starting_scope = include_unlisted ? starting_scope.distributable : starting_scope.with_public_visibility scope != :local_reblogs ? starting_scope.without_reblogs : starting_scope end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 2e3061b07..8a37c7695 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -31,11 +31,8 @@ class FanOutOnWriteService < BaseService return end - return unless status.public_visibility? - - deliver_to_hashtags(status) - - return if status.reply? && status.in_reply_to_account_id != status.account_id && !Setting.show_replies_in_public_timelines + deliver_to_hashtags(status) if status.distributable? + return if !status.public_visibility? || (status.reply? && status.in_reply_to_account_id != status.account_id) deliver_to_media(status) if status.media_attachments.any? deliver_to_public(status) if status.local? diff --git a/app/services/process_hashtags_service.rb b/app/services/process_hashtags_service.rb index 1f0d64323..5ec5ea0c2 100644 --- a/app/services/process_hashtags_service.rb +++ b/app/services/process_hashtags_service.rb @@ -13,7 +13,7 @@ class ProcessHashtagsService < BaseService status.tags << tag records << tag - TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility? + TrendingTags.record_use!(tag, status.account, status.created_at) if status.distributable? end return unless status.distributable? diff --git a/app/services/remove_hashtags_service.rb b/app/services/remove_hashtags_service.rb new file mode 100644 index 000000000..6bf77a068 --- /dev/null +++ b/app/services/remove_hashtags_service.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class RemoveHashtagsService < BaseService + def call(status, tags) + tags = status.tags.matching_name(tags) if tags.is_a?(Array) + + status.account.featured_tags.where(tag: tags).each do |featured_tag| + featured_tag.decrement(status.id) + end + + if status.distributable? + delete_payload = Oj.dump(event: :delete, payload: status.id.to_s) + tags.pluck(:name).each do |hashtag| + redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", delete_payload) + redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", delete_payload) if status.local? + end + end + + status.tags -= tags + end +end diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb index 4d3dc13db..72ef6a9ec 100644 --- a/app/services/remove_status_service.rb +++ b/app/services/remove_status_service.rb @@ -139,7 +139,7 @@ class RemoveStatusService < BaseService featured_tag.decrement(@status.id) end - return unless @status.public_visibility? + return unless @status.distributable? @tags.each do |hashtag| redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload) @@ -148,7 +148,7 @@ class RemoveStatusService < BaseService end def remove_from_public - return unless @status.public_visibility? + return unless @status.distributable? redis.publish('timeline:public', @payload) if @status.local? @@ -159,7 +159,7 @@ class RemoveStatusService < BaseService end def remove_from_media - return unless @status.public_visibility? + return unless @status.distributable? redis.publish('timeline:public:media', @payload) if @status.local? diff --git a/app/services/revoke_status_service.rb b/app/services/revoke_status_service.rb index b7d7a6e18..95810acd2 100644 --- a/app/services/revoke_status_service.rb +++ b/app/services/revoke_status_service.rb @@ -12,7 +12,7 @@ class RevokeStatusService < BaseService @status = status @account = status.account @account_ids = account_ids - @mentions = status.active_mentions.where(account_id: account_ids) + @mentions = status.mentions.where(account_id: account_ids) @reblogs = status.reblogs.where(account_id: account_ids) RedisLock.acquire(lock_options) do |lock| @@ -21,7 +21,7 @@ class RevokeStatusService < BaseService remove_from_lists remove_from_affected remove_reblogs - remove_from_hashtags unless @status.distributable? + remove_from_hashtags remove_from_public remove_from_media remove_from_direct if status.direct_visibility? @@ -62,7 +62,7 @@ class RevokeStatusService < BaseService featured_tag.decrement(@status.id) end - return unless @status.public_visibility? + return unless @status.distributable? @tags.each do |hashtag| redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload) @@ -71,7 +71,7 @@ class RevokeStatusService < BaseService end def remove_from_public - return if @status.public_visibility? + return if @status.distributable? redis.publish('timeline:public', @payload) if @status.local? @@ -82,7 +82,7 @@ class RevokeStatusService < BaseService end def remove_from_media - return if @status.public_visibility? + return if @status.distributable? redis.publish('timeline:public:media', @payload) if @status.local? diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index 015010588..d0e61d153 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -89,13 +89,11 @@ class UpdateStatusService < BaseService featured_tag.decrement(@status.id) end - if @status.public_visibility? - return if @deleted_tag_names.blank? + return unless @status.distributable? && @deleted_tag_names.present? - @deleted_tag_names.each do |hashtag| - redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @delete_payload) - redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @delete_payload) if @status.local? - end + @deleted_tag_names.each do |hashtag| + redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @delete_payload) + redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @delete_payload) if @status.local? end end @@ -124,7 +122,7 @@ class UpdateStatusService < BaseService @status.tags << tag new_tag_ids << tag.id - TrendingTags.record_use!(tag, @account, now) if @status.public_visibility? + TrendingTags.record_use!(tag, @account, now) if @status.distributable? end return unless @status.local? && @status.distributable? -- cgit