Skip to content

Commit

Permalink
Add: #90 スタンプに対応していないと思われるサーバーの投稿からスタンプボタンを隠す設定 (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
kmycode authored Nov 2, 2023
1 parent 77a1cab commit 45cc8ff
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 8 deletions.
5 changes: 3 additions & 2 deletions app/javascript/mastodon/components/status_action_bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';

import DropdownMenuContainer from '../containers/dropdown_menu_container';
import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dropdown_container';
import { enableEmojiReaction , bookmarkCategoryNeeded, simpleTimelineMenu, me } from '../initial_state';
import { enableEmojiReaction , bookmarkCategoryNeeded, simpleTimelineMenu, me, hideEmojiReactionUnavailableServer } from '../initial_state';

import { IconButton } from './icon_button';

Expand Down Expand Up @@ -453,6 +453,7 @@ class StatusActionBar extends ImmutablePureComponent {
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
);

const emojiReactionAvailableServer = !hideEmojiReactionUnavailableServer || status.get('emoji_reaction_available_server');
const emojiReactionPolicy = account.getIn(['other_settings', 'emoji_reaction_policy']) || 'allow';
const following = emojiReactionPolicy !== 'following_only' || (relationship && relationship.get('following'));
const followed = emojiReactionPolicy !== 'followers_only' || (relationship && relationship.get('followed_by'));
Expand All @@ -462,7 +463,7 @@ class StatusActionBar extends ImmutablePureComponent {
const emojiPickerButton = (
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.emojiReaction)} icon='smile-o' iconComponent={EmojiReactionIcon} onClick={this.handleEmojiPickInnerButton} />
);
const emojiPickerDropdown = enableEmojiReaction && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
const emojiPickerDropdown = enableEmojiReaction && emojiReactionAvailableServer && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} />
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router';

import { IconButton } from '../../../components/icon_button';
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
import { enableEmojiReaction , bookmarkCategoryNeeded, me } from '../../../initial_state';
import { enableEmojiReaction , bookmarkCategoryNeeded, me, hideEmojiReactionUnavailableServer } from '../../../initial_state';
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';

const messages = defineMessages({
Expand Down Expand Up @@ -358,6 +358,7 @@ class ActionBar extends PureComponent {
reblogTitle = intl.formatMessage(messages.cannot_reblog);
}

const emojiReactionAvailableServer = !hideEmojiReactionUnavailableServer || status.get('emoji_reaction_available_server');
const emojiReactionPolicy = account.getIn(['other_settings', 'emoji_reaction_policy']) || 'allow';
const following = emojiReactionPolicy !== 'following_only' || (relationship && relationship.get('following'));
const followed = emojiReactionPolicy !== 'followers_only' || (relationship && relationship.get('followed_by'));
Expand All @@ -367,7 +368,7 @@ class ActionBar extends PureComponent {
const emojiPickerButton = (
<IconButton icon='smile-o' iconComponent={EmojiReactionIcon} onClick={this.handleEmojiPickInnerButton} title={intl.formatMessage(messages.pickEmoji)} />
);
const emojiPickerDropdown = enableEmojiReaction && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
const emojiPickerDropdown = enableEmojiReaction && emojiReactionAvailableServer && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
<div className='detailed-status__button'><EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} /></div>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Icon } from 'mastodon/components/icon';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import { SearchabilityIcon } from 'mastodon/components/searchability_icon';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import { enableEmojiReaction } from 'mastodon/initial_state';
import { enableEmojiReaction, hideEmojiReactionUnavailableServer } from 'mastodon/initial_state';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';

import { Avatar } from '../../../components/avatar';
Expand Down Expand Up @@ -233,7 +233,8 @@ class DetailedStatus extends ImmutablePureComponent {
if (status.get('emoji_reactions')) {
const emojiReactions = status.get('emoji_reactions');
const emojiReactionPolicy = status.getIn(['account', 'other_settings', 'emoji_reaction_policy']) || 'allow';
if (emojiReactions.size > 0 && enableEmojiReaction && emojiReactionPolicy !== 'block') {
const emojiReactionAvailableServer = !hideEmojiReactionUnavailableServer || status.get('emoji_reaction_available_server');
if (emojiReactions.size > 0 && enableEmojiReaction && emojiReactionAvailableServer && emojiReactionPolicy !== 'block') {
emojiReactionsBar = <StatusEmojiReactionsBar emojiReactions={emojiReactions} status={status} onEmojiReact={this.props.onEmojiReact} onUnEmojiReact={this.props.onUnEmojiReact} />;
}
}
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/mastodon/initial_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
* @property {boolean} enable_dtl_menu
* @property {boolean=} expand_spoilers
* @property {boolean} hide_blocking_quote
* @property {boolean} hide_emoji_reaction_unavailable_server
* @property {boolean} hide_recent_emojis
* @property {boolean} limited_federation_mode
* @property {string} locale
Expand Down Expand Up @@ -143,6 +144,7 @@ export const enableDtlMenu = getMeta('enable_dtl_menu');
export const expandSpoilers = getMeta('expand_spoilers');
export const forceSingleColumn = !getMeta('advanced_layout');
export const hideBlockingQuote = getMeta('hide_blocking_quote');
export const hideEmojiReactionUnavailableServer = getMeta('hide_emoji_reaction_unavailable_server');
export const hideRecentEmojis = getMeta('hide_recent_emojis');
export const limitedFederationMode = getMeta('limited_federation_mode');
export const mascot = getMeta('mascot');
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/has_user_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ def setting_lock_follow_from_bot
settings['lock_follow_from_bot']
end

def setting_hide_emoji_reaction_unavailable_server
settings['web.hide_emoji_reaction_unavailable_server']
end

def allows_report_emails?
settings['notification_emails.report']
end
Expand Down
32 changes: 32 additions & 0 deletions app/models/instance_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,36 @@
#

class InstanceInfo < ApplicationRecord
EMOJI_REACTION_AVAILABLE_SOFTWARES = %w(
misskey
calckey
cherrypick
meisskey
firefish
renedon
fedibird
kmyblue
pleroma
akkoma
).freeze

def self.emoji_reaction_available?(domain)
return Setting.enable_emoji_reaction if domain.nil?

Rails.cache.fetch("emoji_reaction_available_domain:#{domain}") { fetch_emoji_reaction_available(domain) }
end

def self.fetch_emoji_reaction_available(domain)
return Setting.enable_emoji_reaction if domain.nil?

info = InstanceInfo.find_by(domain: domain)
return false if info.nil?

return true if EMOJI_REACTION_AVAILABLE_SOFTWARES.include?(info['software'])

features = info.data.dig('metadata', 'features')
return false if features.nil? || !features.is_a?(Array)

features.include?('emoji_reaction')
end
end
4 changes: 4 additions & 0 deletions app/models/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ def emoji_reaction_allows_map(status_ids, account_id)
Status.where(id: status_ids).pluck(:account_id).uniq.index_with { |a| Account.find_by(id: a).show_emoji_reaction?(my_account) }
end

def emoji_reaction_availables_map(domains)
domains.index_with { |d| InstanceInfo.emoji_reaction_available?(d) }
end

def reload_stale_associations!(cached_items)
account_ids = []

Expand Down
1 change: 1 addition & 0 deletions app/models/user_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class KeyError < Error; end
setting :show_quote_in_home, default: true
setting :show_quote_in_public, default: false
setting :hide_blocking_quote, default: true
setting :hide_emoji_reaction_unavailable_server, default: false
end

namespace :notification_emails do
Expand Down
4 changes: 3 additions & 1 deletion app/presenters/status_relationships_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class StatusRelationshipsPresenter
PINNABLE_VISIBILITIES = %w(public public_unlisted unlisted login private).freeze

attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map, :blocks_map, :domain_blocks_map,
:bookmarks_map, :filters_map, :attributes_map, :emoji_reaction_allows_map
:bookmarks_map, :filters_map, :attributes_map, :emoji_reaction_allows_map, :emoji_reaction_availables_map

def initialize(statuses, current_account_id = nil, **options)
@current_account_id = current_account_id
Expand All @@ -19,6 +19,7 @@ def initialize(statuses, current_account_id = nil, **options)
@pins_map = {}
@filters_map = {}
@emoji_reaction_allows_map = nil
@emoji_reaction_availables_map = {}
else
statuses = statuses.compact
statuses += statuses.filter_map(&:quote)
Expand All @@ -35,6 +36,7 @@ def initialize(statuses, current_account_id = nil, **options)
@domain_blocks_map = Status.domain_blocks_map(statuses.filter_map { |status| status.account.domain }.uniq, current_account_id).merge(options[:domain_blocks_map] || {})
@pins_map = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {})
@emoji_reaction_allows_map = Status.emoji_reaction_allows_map(status_ids, current_account_id).merge(options[:emoji_reaction_allows_map] || {})
@emoji_reaction_availables_map = Status.emoji_reaction_availables_map(statuses.filter_map { |status| status.account.domain }.uniq).merge(options[:emoji_reaction_availables_map] || {})
@attributes_map = options[:attributes_map] || {}
end
end
Expand Down
1 change: 1 addition & 0 deletions app/serializers/initial_state_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def meta
store[:show_quote_in_home] = object.current_account.user.setting_show_quote_in_home
store[:show_quote_in_public] = object.current_account.user.setting_show_quote_in_public
store[:hide_blocking_quote] = object.current_account.user.setting_hide_blocking_quote
store[:hide_emoji_reaction_unavailable_server] = object.current_account.user.setting_hide_emoji_reaction_unavailable_server
else
store[:auto_play_gif] = Setting.auto_play_gif
store[:display_media] = Setting.display_media
Expand Down
10 changes: 9 additions & 1 deletion app/serializers/rest/status_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
:sensitive, :spoiler_text, :visibility, :visibility_ex, :limited_scope, :language,
:uri, :url, :replies_count, :reblogs_count, :searchability, :markdown,
:status_reference_ids, :status_references_count, :status_referred_by_count,
:status_reference_ids, :status_references_count, :status_referred_by_count, :emoji_reaction_available_server,
:favourites_count, :emoji_reactions, :emoji_reactions_count, :reactions, :edited_at

attribute :favourited, if: :current_user?
Expand Down Expand Up @@ -166,6 +166,14 @@ def show_emoji_reaction?
end
end

def emoji_reaction_available_server
if relationships
relationships.emoji_reaction_availables_map[object.account.domain] || false
else
InstanceInfo.emoji_reaction_available?(object.account.domain)
end
end

def reactions
emoji_reactions.tap do |rs|
rs.each do |emoji_reaction|
Expand Down
1 change: 1 addition & 0 deletions app/views/settings/preferences/appearance/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- if Setting.enable_emoji_reaction
= ff.input :'web.enable_emoji_reaction', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_enable_emoji_reaction'), hint: I18n.t('simple_form.hints.defaults.setting_enable_emoji_reaction')
= ff.input :'web.show_emoji_reaction_on_timeline', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_show_emoji_reaction_on_timeline')
= ff.input :'web.hide_emoji_reaction_unavailable_server', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_hide_emoji_reaction_unavailable_server')

.fields-group
= ff.input :'web.bookmark_category_needed', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_bookmark_category_needed'), hint: I18n.t('simple_form.hints.defaults.setting_bookmark_category_needed')
Expand Down
1 change: 1 addition & 0 deletions config/locales/simple_form.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ en:
outside_only: Followings or followers only
setting_expand_spoilers: Always expand posts marked with content warnings
setting_hide_blocking_quote: Hide posts which have a quote written by the user you are blocking
setting_hide_emoji_reaction_unavailable_server: Hide stamp button from unavailable server
setting_hide_followers_count: Hide followers count
setting_hide_following_count: Hide following count
setting_hide_network: Hide your social graph
Expand Down
1 change: 1 addition & 0 deletions config/locales/simple_form.ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ ja:
setting_enable_emoji_reaction: スタンプ機能を使用する
setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する
setting_hide_blocking_quote: ブロックしたユーザーの投稿を引用した投稿を隠す
setting_hide_emoji_reaction_unavailable_server: スタンプに対応していないと思われるサーバーの投稿からスタンプボタンを隠す
setting_hide_followers_count: フォロワー数を隠す
setting_hide_following_count: フォロー数を隠す
setting_hide_network: 繋がりを隠す
Expand Down
39 changes: 39 additions & 0 deletions spec/models/status_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,45 @@
end
end

describe '.emoji_reaction_availables_map' do
subject { described_class.emoji_reaction_availables_map(domains) }

let(:domains) { %w(features_available.com features_unavailable.com features_invalid.com features_nil.com no_info.com mastodon.com misskey.com) }

before do
Fabricate(:instance_info, domain: 'features_available.com', software: 'mastodon', data: { metadata: { features: ['emoji_reaction'] } })
Fabricate(:instance_info, domain: 'features_unavailable.com', software: 'mastodon', data: { metadata: { features: ['ohagi'] } })
Fabricate(:instance_info, domain: 'features_invalid.com', software: 'mastodon', data: { metadata: { features: 'good_for_ohagi' } })
Fabricate(:instance_info, domain: 'features_nil.com', software: 'mastodon', data: { metadata: { features: nil } })
Fabricate(:instance_info, domain: 'mastodon.com', software: 'mastodon')
Fabricate(:instance_info, domain: 'misskey.com', software: 'misskey')
end

it 'availables if features contains emoji_reaction' do
expect(subject['features_available.com']).to be true
end

it 'unavailables if features does not contain emoji_reaction' do
expect(subject['features_unavailable.com']).to be false
end

it 'unavailables if features is not valid' do
expect(subject['features_invalid.com']).to be false
end

it 'unavailables if features is nil' do
expect(subject['features_nil.com']).to be false
end

it 'unavailables if mastodon server' do
expect(subject['mastodon.com']).to be false
end

it 'availables if misskey server' do
expect(subject['misskey.com']).to be true
end
end

describe '.tagged_with' do
let(:tag_cats) { Fabricate(:tag, name: 'cats') }
let(:tag_dogs) { Fabricate(:tag, name: 'dogs') }
Expand Down

0 comments on commit 45cc8ff

Please sign in to comment.