Merge branch 'kb_development' into kb_migration
This commit is contained in:
commit
74d4062f9d
60 changed files with 647 additions and 514 deletions
|
@ -15,6 +15,10 @@ class Api::V1::Statuses::EmojiReactionedByAccountsController < Api::BaseControll
|
|||
private
|
||||
|
||||
def load_accounts
|
||||
return [] unless Setting.enable_emoji_reaction
|
||||
return [] if current_account.nil? && @status.account.emoji_reaction_policy != :allow
|
||||
return [] if current_account.present? && !@status.account.show_emoji_reaction?(current_account)
|
||||
|
||||
scope = default_accounts
|
||||
scope = scope.where.not(account_id: current_account.excluded_from_timeline_account_ids) unless current_account.nil?
|
||||
scope.merge(paginated_emoji_reactions).to_a
|
||||
|
|
|
@ -42,6 +42,7 @@ class Api::V1::Statuses::EmojiReactionsController < Api::BaseController
|
|||
def create_private(emoji)
|
||||
count = EmojiReaction.where(account: current_account, status: @status).count
|
||||
raise Mastodon::ValidationError, I18n.t('reactions.errors.limit_reached') if count >= EmojiReaction::EMOJI_REACTION_PER_ACCOUNT_LIMIT
|
||||
raise Mastodon::ValidationError, I18n.t('reactions.errors.disabled') unless Setting.enable_emoji_reaction
|
||||
|
||||
EmojiReactService.new.call(current_account, @status, emoji)
|
||||
render json: @status, serializer: REST::StatusSerializer
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Settings::Preferences::ReachingController < Settings::Preferences::BaseController
|
||||
private
|
||||
|
||||
def after_update_redirect_path
|
||||
settings_preferences_reaching_path
|
||||
end
|
||||
end
|
|
@ -18,7 +18,7 @@ import Card from '../features/status/components/card';
|
|||
// to use the progress bar to show download progress
|
||||
import Bundle from '../features/ui/components/bundle';
|
||||
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
|
||||
import { displayMedia } from '../initial_state';
|
||||
import { displayMedia, enableEmojiReaction, showEmojiReactionOnTimeline } from '../initial_state';
|
||||
|
||||
import { Avatar } from './avatar';
|
||||
import { AvatarOverlay } from './avatar_overlay';
|
||||
|
@ -577,8 +577,8 @@ class Status extends ImmutablePureComponent {
|
|||
let emojiReactionsBar = null;
|
||||
if (!this.props.withoutEmojiReactions && status.get('emoji_reactions')) {
|
||||
const emojiReactions = status.get('emoji_reactions');
|
||||
if (emojiReactions.size > 0) {
|
||||
emojiReactionsBar = <StatusEmojiReactionsBar emojiReactions={emojiReactions} status={status} onEmojiReact={this.props.onEmojiReact} onUnEmojiReact={this.props.onUnEmojiReact} />;
|
||||
if (emojiReactions.size > 0 && enableEmojiReaction) {
|
||||
emojiReactionsBar = <StatusEmojiReactionsBar emojiReactions={emojiReactions} myReactionOnly={!showEmojiReactionOnTimeline} status={status} onEmojiReact={this.props.onEmojiReact} onUnEmojiReact={this.props.onUnEmojiReact} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -622,7 +622,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
{(!isCardMediaWithSensitive || !status.get('hidden')) && media}
|
||||
|
||||
{expanded && hashtagBar}
|
||||
{(!status.get('spoiler_text') || expanded) && hashtagBar}
|
||||
|
||||
{emojiReactionsBar}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
|
||||
|
||||
import DropdownMenuContainer from '../containers/dropdown_menu_container';
|
||||
import EmojiPickerDropdown from '../features/compose/containers/emoji_picker_dropdown_container';
|
||||
import { bookmarkCategoryNeeded, me } from '../initial_state';
|
||||
import { enableEmojiReaction , bookmarkCategoryNeeded, me } from '../initial_state';
|
||||
|
||||
import { IconButton } from './icon_button';
|
||||
|
||||
|
@ -409,13 +410,16 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
|
||||
);
|
||||
|
||||
const following = !account.getIn(['other_settings', 'emoji_reaction_must_follower']) || (relationship && relationship.get('following'));
|
||||
const followed = !account.getIn(['other_settings', 'emoji_reaction_must_following']) || (relationship && relationship.get('followed_by'));
|
||||
const denyFromAll = !account.getIn(['other_settings', 'emoji_reaction_deny_from_all']);
|
||||
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'));
|
||||
const mutual = emojiReactionPolicy !== 'mutuals_only' || (relationship && relationship.get('following') && relationship.get('followed_by'));
|
||||
const outside = emojiReactionPolicy !== 'outside_only' || (relationship && (relationship.get('following') || relationship.get('followed_by')));
|
||||
const denyFromAll = emojiReactionPolicy !== 'block' && emojiReactionPolicy !== 'block';
|
||||
const emojiPickerButton = (
|
||||
<IconButton className='status__action-bar__button' title={intl.formatMessage(messages.emojiReaction)} icon='smile-o' onClick={this.handleEmojiPickInnerButton} />
|
||||
);
|
||||
const emojiPickerDropdown = (writtenByMe || ((denyFromAll) && (following) && (followed))) && (
|
||||
const emojiPickerDropdown = enableEmojiReaction && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
|
||||
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} />
|
||||
);
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ class StatusEmojiReactionsBar extends PureComponent {
|
|||
status: ImmutablePropTypes.map,
|
||||
onEmojiReact: PropTypes.func,
|
||||
onUnEmojiReact: PropTypes.func,
|
||||
myReactionOnly: PropTypes.bool,
|
||||
};
|
||||
|
||||
onEmojiReact = (name) => {
|
||||
|
@ -73,20 +74,23 @@ class StatusEmojiReactionsBar extends PureComponent {
|
|||
};
|
||||
|
||||
render () {
|
||||
const { emojiReactions } = this.props;
|
||||
const { emojiReactions, myReactionOnly } = this.props;
|
||||
|
||||
const emojiButtons = Array.from(emojiReactions).filter(emoji => emoji.get('count') !== 0).map((emoji, index) => (
|
||||
<EmojiReactionButton
|
||||
key={index}
|
||||
name={emoji.get('name')}
|
||||
count={emoji.get('count')}
|
||||
me={emoji.get('me')}
|
||||
url={emoji.get('url')}
|
||||
staticUrl={emoji.get('static_url')}
|
||||
domain={emoji.get('domain')}
|
||||
onEmojiReact={this.onEmojiReact}
|
||||
onUnEmojiReact={this.onUnEmojiReact}
|
||||
/>));
|
||||
const emojiButtons = Array.from(emojiReactions)
|
||||
.filter(emoji => emoji.get('count') !== 0)
|
||||
.filter(emoji => !myReactionOnly || emoji.get('me'))
|
||||
.map((emoji, index) => (
|
||||
<EmojiReactionButton
|
||||
key={index}
|
||||
name={emoji.get('name')}
|
||||
count={myReactionOnly ? 1 : emoji.get('count')}
|
||||
me={emoji.get('me')}
|
||||
url={emoji.get('url')}
|
||||
staticUrl={emoji.get('static_url')}
|
||||
domain={emoji.get('domain')}
|
||||
onEmojiReact={this.onEmojiReact}
|
||||
onUnEmojiReact={this.onUnEmojiReact}
|
||||
/>));
|
||||
|
||||
return (
|
||||
<div className='status__emoji-reactions-bar'>
|
||||
|
|
|
@ -10,9 +10,10 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||
|
||||
|
||||
import { IconButton } from '../../../components/icon_button';
|
||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||
import { bookmarkCategoryNeeded, me } from '../../../initial_state';
|
||||
import { enableEmojiReaction , bookmarkCategoryNeeded, me } from '../../../initial_state';
|
||||
import EmojiPickerDropdown from '../../compose/containers/emoji_picker_dropdown_container';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -305,10 +306,6 @@ class ActionBar extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const emojiPickerButton = (
|
||||
<IconButton icon='smile-o' onClick={this.handleEmojiPickInnerButton} title={intl.formatMessage(messages.pickEmoji)} />
|
||||
);
|
||||
|
||||
let replyIcon;
|
||||
if (status.get('in_reply_to_id', null) === null) {
|
||||
replyIcon = 'reply';
|
||||
|
@ -329,13 +326,26 @@ class ActionBar extends PureComponent {
|
|||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||
}
|
||||
|
||||
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'));
|
||||
const mutual = emojiReactionPolicy !== 'mutuals_only' || (relationship && relationship.get('following') && relationship.get('followed_by'));
|
||||
const outside = emojiReactionPolicy !== 'outside_only' || (relationship && (relationship.get('following') || relationship.get('followed_by')));
|
||||
const denyFromAll = emojiReactionPolicy !== 'block' && emojiReactionPolicy !== 'block';
|
||||
const emojiPickerButton = (
|
||||
<IconButton icon='smile-o' onClick={this.handleEmojiPickInnerButton} title={intl.formatMessage(messages.pickEmoji)} />
|
||||
);
|
||||
const emojiPickerDropdown = enableEmojiReaction && denyFromAll && (writtenByMe || (following && followed && mutual && outside)) && (
|
||||
<div className='detailed-status__button'><EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} /></div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className='detailed-status__action-bar'>
|
||||
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
|
||||
<div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>
|
||||
<div className='detailed-status__button'><EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={emojiPickerButton} /></div>
|
||||
{emojiPickerDropdown}
|
||||
|
||||
<div className='detailed-status__action-bar-dropdown'>
|
||||
<DropdownMenuContainer size={18} icon='ellipsis-h' status={status} items={menu} direction='left' title={intl.formatMessage(messages.more)} />
|
||||
|
|
|
@ -13,6 +13,7 @@ import EditedTimestamp from 'mastodon/components/edited_timestamp';
|
|||
import { getHashtagBarForStatus } from 'mastodon/components/hashtag_bar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
|
||||
import { enableEmojiReaction } from 'mastodon/initial_state';
|
||||
|
||||
import { Avatar } from '../../../components/avatar';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
|
@ -240,7 +241,8 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
let emojiReactionsBar = null;
|
||||
if (status.get('emoji_reactions')) {
|
||||
const emojiReactions = status.get('emoji_reactions');
|
||||
if (emojiReactions.size > 0) {
|
||||
const emojiReactionPolicy = status.getIn(['account', 'other_settings', 'emoji_reaction_policy']) || 'allow';
|
||||
if (emojiReactions.size > 0 && enableEmojiReaction && emojiReactionPolicy !== 'block') {
|
||||
emojiReactionsBar = <StatusEmojiReactionsBar emojiReactions={emojiReactions} status={status} onEmojiReact={this.props.onEmojiReact} onUnEmojiReact={this.props.onUnEmojiReact} />;
|
||||
}
|
||||
}
|
||||
|
@ -398,7 +400,7 @@ class DetailedStatus extends ImmutablePureComponent {
|
|||
|
||||
{(!isCardMediaWithSensitive || !status.get('hidden')) && media}
|
||||
|
||||
{expanded && hashtagBar}
|
||||
{(!status.get('spoiler_text') || expanded) && hashtagBar}
|
||||
|
||||
{emojiReactionsBar}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
* @property {boolean} display_media_expand
|
||||
* @property {string} domain
|
||||
* @property {string} dtl_tag
|
||||
* @property {boolean} enable_emoji_reaction
|
||||
* @property {boolean} enable_login_privacy
|
||||
* @property {boolean} enable_dtl_menu
|
||||
* @property {boolean=} expand_spoilers
|
||||
|
@ -75,6 +76,7 @@
|
|||
* @property {string} repository
|
||||
* @property {boolean} search_enabled
|
||||
* @property {boolean} trends_enabled
|
||||
* @property {boolean} show_emoji_reaction_on_timeline
|
||||
* @property {boolean} single_user_mode
|
||||
* @property {string} source_url
|
||||
* @property {string} streaming_api_base_url
|
||||
|
@ -126,6 +128,7 @@ export const displayMedia = getMeta('display_media');
|
|||
export const displayMediaExpand = getMeta('display_media_expand');
|
||||
export const domain = getMeta('domain');
|
||||
export const dtlTag = getMeta('dtl_tag');
|
||||
export const enableEmojiReaction = getMeta('enable_emoji_reaction');
|
||||
export const enableLoginPrivacy = getMeta('enable_login_privacy');
|
||||
export const enableDtlMenu = getMeta('enable_dtl_menu');
|
||||
export const expandSpoilers = getMeta('expand_spoilers');
|
||||
|
@ -142,6 +145,7 @@ export const registrationsOpen = getMeta('registrations_open');
|
|||
export const repository = getMeta('repository');
|
||||
export const searchEnabled = getMeta('search_enabled');
|
||||
export const trendsEnabled = getMeta('trends_enabled');
|
||||
export const showEmojiReactionOnTimeline = getMeta('show_emoji_reaction_on_timeline');
|
||||
export const showTrends = getMeta('show_trends');
|
||||
export const singleUserMode = getMeta('single_user_mode');
|
||||
export const source_url = getMeta('source_url');
|
||||
|
|
|
@ -32,7 +32,11 @@ textarea {
|
|||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
.compose-form .compose-form__warning {
|
||||
.compose-form .compose-form__warning,
|
||||
.reply-indicator__content,
|
||||
.reply-indicator__display-name,
|
||||
.reply-indicator__cancel,
|
||||
.autosuggest-textarea__suggestions__item {
|
||||
color: $ui-base-color;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
|
|||
def perform
|
||||
@original_status = status_from_uri(object_uri)
|
||||
|
||||
return if @original_status.nil? || !@original_status.account.local? || delete_arrived_first?(@json['id']) || reject_favourite?
|
||||
return if @original_status.nil? || delete_arrived_first?(@json['id']) || reject_favourite?
|
||||
|
||||
if shortcode.nil?
|
||||
process_favourite
|
||||
|
@ -32,6 +32,8 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
|
|||
end
|
||||
|
||||
def process_emoji_reaction
|
||||
return if !@original_status.account.local? && !Setting.receive_other_servers_emoji_reaction
|
||||
|
||||
if emoji_tag.present?
|
||||
return if emoji_tag['id'].blank? || emoji_tag['name'].blank? || emoji_tag['icon'].blank? || emoji_tag['icon']['url'].blank?
|
||||
|
||||
|
@ -106,10 +108,10 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
|
|||
end
|
||||
|
||||
def write_stream(emoji_reaction)
|
||||
emoji_group = @original_status.emoji_reactions_grouped_by_name
|
||||
emoji_group = @original_status.emoji_reactions_grouped_by_name(nil, force: true)
|
||||
.find { |reaction_group| reaction_group['name'] == emoji_reaction.name && (!reaction_group.key?(:domain) || reaction_group['domain'] == emoji_reaction.custom_emoji&.domain) }
|
||||
emoji_group['status_id'] = @original_status.id.to_s
|
||||
DeliveryEmojiReactionWorker.perform_async(render_emoji_reaction(emoji_group), @original_status.id, emoji_reaction.account_id)
|
||||
DeliveryEmojiReactionWorker.perform_async(render_emoji_reaction(emoji_group), @original_status.id, emoji_reaction.account_id) if @original_status.local? || Setting.streaming_other_servers_emoji_reaction
|
||||
end
|
||||
|
||||
def render_emoji_reaction(emoji_group)
|
||||
|
|
|
@ -149,7 +149,7 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
|
|||
emoji_group = { 'name' => emoji_reaction.name, 'count' => 0, 'account_ids' => [], 'status_id' => @original_status.id.to_s }
|
||||
emoji_group['domain'] = emoji_reaction.custom_emoji.domain if emoji_reaction.custom_emoji
|
||||
end
|
||||
DeliveryEmojiReactionWorker.perform_async(render_emoji_reaction(emoji_group), @original_status.id, emoji_reaction.account_id)
|
||||
DeliveryEmojiReactionWorker.perform_async(render_emoji_reaction(emoji_group), @original_status.id, emoji_reaction.account_id) if @original_status.local? || Setting.streaming_other_servers_emoji_reaction
|
||||
end
|
||||
|
||||
def render_emoji_reaction(emoji_group)
|
||||
|
|
|
@ -61,19 +61,19 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
when 'library'
|
||||
[StatusesIndex]
|
||||
else
|
||||
[PublicStatusesIndex, StatusesIndex]
|
||||
@options[:current_account].user&.setting_use_public_index ? [PublicStatusesIndex, StatusesIndex] : [StatusesIndex]
|
||||
end
|
||||
end
|
||||
|
||||
def default_filter
|
||||
definition_should = [
|
||||
default_should1,
|
||||
default_should2,
|
||||
non_publicly_searchable,
|
||||
public_index,
|
||||
searchability_limited,
|
||||
]
|
||||
definition_should << searchability_public if %i(public).include?(@searchability)
|
||||
definition_should << searchability_private if %i(public unlisted private).include?(@searchability)
|
||||
definition_should << searchable_by_me if %i(public unlisted private direct).include?(@searchability)
|
||||
definition_should << self_posts if %i(public unlisted private direct).exclude?(@searchability)
|
||||
|
||||
{
|
||||
bool: {
|
||||
|
@ -83,7 +83,7 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
}
|
||||
end
|
||||
|
||||
def default_should1
|
||||
def public_index
|
||||
{
|
||||
term: {
|
||||
_index: PublicStatusesIndex.index_name,
|
||||
|
@ -91,24 +91,7 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
}
|
||||
end
|
||||
|
||||
def default_should2
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
term: { _index: StatusesIndex.index_name },
|
||||
},
|
||||
{
|
||||
term: {
|
||||
searchable_by: @options[:current_account].id,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def non_publicly_searchable
|
||||
def searchable_by_me
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
|
@ -128,6 +111,21 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
}
|
||||
end
|
||||
|
||||
def self_posts
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
term: { _index: StatusesIndex.index_name },
|
||||
},
|
||||
{
|
||||
term: { account_id: @options[:current_account].id },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def searchability_public
|
||||
{
|
||||
bool: {
|
||||
|
@ -349,6 +347,6 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
end
|
||||
|
||||
rule(query: sequence(:clauses)) do
|
||||
Query.new(clauses, current_account: current_account)
|
||||
Query.new(clauses, current_account: current_account, searchability: searchability)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,8 @@ class StatusCacheHydrator
|
|||
end
|
||||
|
||||
def hydrate(account_id)
|
||||
account = Account.find(account_id)
|
||||
|
||||
# The cache of the serialized hash is generated by the fan-out-on-write service
|
||||
payload = Rails.cache.fetch("fan-out/#{@status.id}") { InlineRenderer.render(@status, nil, :status) }
|
||||
|
||||
|
@ -33,6 +35,7 @@ class StatusCacheHydrator
|
|||
payload[:reblog][:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.reblog_of_id).exists?
|
||||
payload[:reblog][:pinned] = StatusPin.where(account_id: account_id, status_id: @status.reblog_of_id).exists? if @status.reblog.account_id == account_id
|
||||
payload[:reblog][:filtered] = payload[:filtered]
|
||||
payload[:reblog][:emoji_reactions] = @status.emoji_reactions_grouped_by_name(account)
|
||||
|
||||
if payload[:reblog][:poll]
|
||||
if @status.reblog.account_id == account_id
|
||||
|
@ -56,6 +59,7 @@ class StatusCacheHydrator
|
|||
payload[:filtered] = CustomFilter
|
||||
.apply_cached_filters(CustomFilter.cached_filters_for(account_id), @status, following?(account_id))
|
||||
.map { |filter| serialized_filter(filter) }
|
||||
payload[:emoji_reactions] = @status.emoji_reactions_grouped_by_name(account)
|
||||
|
||||
if payload[:poll]
|
||||
payload[:poll][:voted] = @status.account_id == account_id
|
||||
|
|
|
@ -363,28 +363,37 @@ class Account < ApplicationRecord
|
|||
false
|
||||
end
|
||||
|
||||
def emoji_reactions_must_following?
|
||||
return false unless Setting.enable_block_emoji_reaction_settings
|
||||
return user&.settings&.[]('emoji_reactions.must_be_following') || false if user.present?
|
||||
return settings['emoji_reactions_must_be_following'] || false if settings.present?
|
||||
def emoji_reaction_policy
|
||||
return settings['emoji_reaction_policy']&.to_sym || :allow if settings.present? && user.nil?
|
||||
return :allow if user.nil?
|
||||
return :block if local? && !Setting.enable_emoji_reaction
|
||||
|
||||
false
|
||||
user.setting_emoji_reaction_policy&.to_sym
|
||||
end
|
||||
|
||||
def emoji_reactions_must_follower?
|
||||
return false unless Setting.enable_block_emoji_reaction_settings
|
||||
return user&.settings&.[]('emoji_reactions.must_be_follower') || false if user.present?
|
||||
return settings['emoji_reaction_must_be_follower'] || false if settings.present?
|
||||
def show_emoji_reaction?(account)
|
||||
return false unless Setting.enable_emoji_reaction
|
||||
|
||||
false
|
||||
case emoji_reaction_policy
|
||||
when :block
|
||||
false
|
||||
when :following_only
|
||||
account.present? && (id == account.id || following?(account))
|
||||
when :followers_only
|
||||
account.present? && (id == account.id || followed_by?(account))
|
||||
when :mutuals_only
|
||||
account.present? && (id == account.id || mutual?(account))
|
||||
when :outside_only
|
||||
account.present? && (id == account.id || following?(account) || followed_by?(account))
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def emoji_reactions_deny_from_all?
|
||||
return false unless Setting.enable_block_emoji_reaction_settings
|
||||
return user&.settings&.[]('emoji_reactions.deny_from_all') || false if user.present?
|
||||
return settings['emoji_reaction_deny_from_all'] || false if settings.present?
|
||||
def allow_emoji_reaction?(account)
|
||||
return false if account.nil?
|
||||
|
||||
false
|
||||
show_emoji_reaction?(account)
|
||||
end
|
||||
|
||||
def public_settings
|
||||
|
@ -398,17 +407,27 @@ class Account < ApplicationRecord
|
|||
'translatable_private' => translatable_private?,
|
||||
'link_preview' => link_preview?,
|
||||
}
|
||||
if Setting.enable_block_emoji_reaction_settings
|
||||
if Setting.enable_emoji_reaction
|
||||
config = config.merge({
|
||||
'emoji_reaction_must_following' => emoji_reactions_must_following?,
|
||||
'emoji_reaction_must_follower' => emoji_reactions_must_follower?,
|
||||
'emoji_reaction_deny_from_all' => emoji_reactions_deny_from_all?,
|
||||
'emoji_reaction_policy' => emoji_reaction_policy,
|
||||
})
|
||||
end
|
||||
config = config.merge(settings) if settings.present?
|
||||
config
|
||||
end
|
||||
|
||||
def public_settings_for_local
|
||||
config = public_settings
|
||||
|
||||
unless Setting.enable_emoji_reaction
|
||||
config = config.merge({
|
||||
'emoji_reaction_policy' => :block,
|
||||
})
|
||||
end
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
def previous_strikes_count
|
||||
strikes.where(overruled_at: nil).count
|
||||
end
|
||||
|
|
|
@ -211,6 +211,10 @@ module AccountInteractions
|
|||
other_account.following?(self)
|
||||
end
|
||||
|
||||
def mutual?(other_account)
|
||||
following?(other_account) && followed_by?(other_account)
|
||||
end
|
||||
|
||||
def blocking?(other_account)
|
||||
block_relationships.where(target_account: other_account).exists?
|
||||
end
|
||||
|
|
|
@ -43,6 +43,14 @@ module HasUserSettings
|
|||
settings['web.hide_recent_emojis']
|
||||
end
|
||||
|
||||
def setting_enable_emoji_reaction
|
||||
settings['web.enable_emoji_reaction']
|
||||
end
|
||||
|
||||
def setting_show_emoji_reaction_on_timeline
|
||||
settings['web.show_emoji_reaction_on_timeline']
|
||||
end
|
||||
|
||||
def setting_default_sensitive
|
||||
settings['default_sensitive']
|
||||
end
|
||||
|
@ -75,6 +83,10 @@ module HasUserSettings
|
|||
false
|
||||
end
|
||||
|
||||
def setting_emoji_reaction_policy
|
||||
settings['emoji_reaction_policy']
|
||||
end
|
||||
|
||||
def setting_unfollow_modal
|
||||
settings['web.unfollow_modal']
|
||||
end
|
||||
|
@ -204,7 +216,15 @@ module HasUserSettings
|
|||
end
|
||||
|
||||
def setting_default_searchability
|
||||
settings['default_searchability'] || 'private'
|
||||
settings['default_searchability'] || 'direct'
|
||||
end
|
||||
|
||||
def setting_default_searchability_of_search
|
||||
settings['default_searchability_of_search']
|
||||
end
|
||||
|
||||
def setting_use_public_index
|
||||
settings['use_public_index']
|
||||
end
|
||||
|
||||
def setting_disallow_unlisted_public_searchability
|
||||
|
|
|
@ -18,7 +18,7 @@ class EmojiReaction < ApplicationRecord
|
|||
include Paginable
|
||||
|
||||
EMOJI_REACTION_LIMIT = 32_767
|
||||
EMOJI_REACTION_PER_ACCOUNT_LIMIT = 3
|
||||
EMOJI_REACTION_PER_ACCOUNT_LIMIT = ENV.fetch('EMOJI_REACTION_PER_ACCOUNT_LIMIT', 3)
|
||||
|
||||
update_index('statuses', :status)
|
||||
|
||||
|
|
|
@ -37,12 +37,14 @@ class Form::AdminSettings
|
|||
status_page_url
|
||||
captcha_enabled
|
||||
ng_words
|
||||
enable_block_emoji_reaction_settings
|
||||
hide_local_users_for_anonymous
|
||||
post_hash_tags_max
|
||||
sensitive_words
|
||||
sensitive_words_for_full
|
||||
authorized_fetch
|
||||
receive_other_servers_emoji_reaction
|
||||
streaming_other_servers_emoji_reaction
|
||||
enable_emoji_reaction
|
||||
).freeze
|
||||
|
||||
INTEGER_KEYS = %i(
|
||||
|
@ -64,9 +66,11 @@ class Form::AdminSettings
|
|||
noindex
|
||||
require_invite_text
|
||||
captcha_enabled
|
||||
enable_block_emoji_reaction_settings
|
||||
hide_local_users_for_anonymous
|
||||
authorized_fetch
|
||||
receive_other_servers_emoji_reaction
|
||||
streaming_other_servers_emoji_reaction
|
||||
enable_emoji_reaction
|
||||
).freeze
|
||||
|
||||
UPLOAD_KEYS = %i(
|
||||
|
|
|
@ -349,14 +349,25 @@ class Status < ApplicationRecord
|
|||
update_status_stat!(status_referred_by_count: [public_send(:status_referred_by_count) + diff, 0].max)
|
||||
end
|
||||
|
||||
def emoji_reactions_grouped_by_name(account = nil)
|
||||
def emoji_reactions_grouped_by_name(account = nil, **options)
|
||||
return [] if account.present? && !self.account.show_emoji_reaction?(account)
|
||||
return [] if account.nil? && !options[:force] && self.account.emoji_reaction_policy != :allow
|
||||
|
||||
(Oj.load(status_stat&.emoji_reactions || '', mode: :strict) || []).tap do |emoji_reactions|
|
||||
if account.present?
|
||||
remove_emoji_reactions = []
|
||||
emoji_reactions.each do |emoji_reaction|
|
||||
emoji_reaction['me'] = emoji_reaction['account_ids'].include?(account.id.to_s)
|
||||
emoji_reaction['account_ids'] -= account.excluded_from_timeline_account_ids.map(&:to_s)
|
||||
|
||||
accounts = Account.where(id: emoji_reaction['account_ids'], silenced_at: nil, suspended_at: nil)
|
||||
accounts = accounts.where('domain IS NULL OR domain NOT IN (?)', account.excluded_from_timeline_domains) if account.excluded_from_timeline_domains.size.positive?
|
||||
emoji_reaction['account_ids'] = accounts.pluck(:id).map(&:to_s)
|
||||
|
||||
emoji_reaction['count'] = emoji_reaction['account_ids'].size
|
||||
remove_emoji_reactions << emoji_reaction if emoji_reaction['count'] <= 0
|
||||
end
|
||||
emoji_reactions - remove_emoji_reactions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ class Trends::Tags < Trends::Base
|
|||
}
|
||||
|
||||
def register(status, at_time = Time.now.utc)
|
||||
return unless !status.reblog? && status.public_visibility? && !status.account.silenced?
|
||||
return unless !status.reblog? && %i(public public_unlisted login).include?(status.visibility.to_sym) && !status.account.silenced?
|
||||
|
||||
status.tags.each do |tag|
|
||||
add(tag, status.account_id, at_time) if tag.usable?
|
||||
|
|
|
@ -26,6 +26,8 @@ class UserSettings
|
|||
setting :stay_privacy, default: false
|
||||
setting :default_reblog_privacy, default: nil
|
||||
setting :default_searchability, default: :direct, in: %w(public private direct limited)
|
||||
setting :default_searchability_of_search, default: :public, in: %w(public private direct limited)
|
||||
setting :use_public_index, default: true
|
||||
setting :disallow_unlisted_public_searchability, default: false
|
||||
setting :public_post_to_unlisted, default: false
|
||||
setting :reject_public_unlisted_subscription, default: false
|
||||
|
@ -34,6 +36,7 @@ class UserSettings
|
|||
setting :reaction_deck, default: nil
|
||||
setting :stop_emoji_reaction_streaming, default: false
|
||||
setting :emoji_reaction_streaming_notify_impl2, default: false
|
||||
setting :emoji_reaction_policy, default: :allow, in: %w(allow outside_only followers_only following_only mutuals_only block)
|
||||
setting :unsafe_limited_distribution, default: false
|
||||
setting :dtl_force_with_tag, default: :none, in: %w(full searchability none)
|
||||
setting :dtl_force_subscribable, default: false
|
||||
|
@ -52,6 +55,8 @@ class UserSettings
|
|||
setting :enable_login_privacy, default: false
|
||||
setting :enable_dtl_menu, default: false
|
||||
setting :hide_recent_emojis, default: false
|
||||
setting :enable_emoji_reaction, default: true
|
||||
setting :show_emoji_reaction_on_timeline, default: true
|
||||
setting :reblog_modal, default: false
|
||||
setting :unfollow_modal, default: true
|
||||
setting :reduce_motion, default: false
|
||||
|
@ -80,12 +85,6 @@ class UserSettings
|
|||
setting :must_be_following_dm, default: false
|
||||
end
|
||||
|
||||
namespace :emoji_reactions do
|
||||
setting :must_be_follower, default: false
|
||||
setting :must_be_following, default: false
|
||||
setting :deny_from_all, default: false
|
||||
end
|
||||
|
||||
def initialize(original_hash)
|
||||
@original_hash = original_hash || {}
|
||||
end
|
||||
|
|
|
@ -48,6 +48,8 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:display_media] = object.current_account.user.setting_display_media
|
||||
store[:display_media_expand] = object.current_account.user.setting_display_media_expand
|
||||
store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
|
||||
store[:enable_emoji_reaction] = object.current_account.user.setting_enable_emoji_reaction
|
||||
store[:show_emoji_reaction_on_timeline] = object.current_account.user.setting_show_emoji_reaction_on_timeline
|
||||
store[:enable_login_privacy] = object.current_account.user.setting_enable_login_privacy
|
||||
store[:enable_dtl_menu] = object.current_account.user.setting_enable_dtl_menu
|
||||
store[:hide_recent_emojis] = object.current_account.user.setting_hide_recent_emojis
|
||||
|
@ -63,6 +65,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:display_media] = Setting.display_media
|
||||
store[:reduce_motion] = Setting.reduce_motion
|
||||
store[:use_blurhash] = Setting.use_blurhash
|
||||
store[:enable_emoji_reaction] = Setting.enable_emoji_reaction
|
||||
end
|
||||
|
||||
store[:disabled_account_id] = object.disabled_account.id.to_s if object.disabled_account
|
||||
|
|
|
@ -168,6 +168,6 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def other_settings
|
||||
object.suspended? ? {} : object.public_settings
|
||||
object.suspended? ? {} : object.public_settings_for_local
|
||||
end
|
||||
end
|
||||
|
|
|
@ -108,7 +108,6 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
# for third party apps
|
||||
def fedibird_capabilities
|
||||
capabilities = [
|
||||
:emoji_reaction,
|
||||
:kmyblue_visibility_public_unlisted,
|
||||
:enable_wide_emoji,
|
||||
:enable_wide_emoji_reaction,
|
||||
|
@ -126,6 +125,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
|
|||
]
|
||||
|
||||
capabilities << :profile_search unless Chewy.enabled?
|
||||
capabilities << :emoji_reaction if Setting.enable_emoji_reaction
|
||||
|
||||
capabilities
|
||||
end
|
||||
|
|
|
@ -125,6 +125,16 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
object.emoji_reactions_grouped_by_name(current_user&.account)
|
||||
end
|
||||
|
||||
def emoji_reactions_count
|
||||
if current_user&.account.nil?
|
||||
return 0 unless Setting.enable_emoji_reaction
|
||||
|
||||
object.account.emoji_reaction_policy == :allow ? object.emoji_reactions_count : 0
|
||||
else
|
||||
object.account.show_emoji_reaction?(current_user.account) ? object.emoji_reactions_count : 0
|
||||
end
|
||||
end
|
||||
|
||||
def reactions
|
||||
emoji_reactions.tap do |rs|
|
||||
rs.each do |emoji_reaction|
|
||||
|
|
|
@ -117,7 +117,6 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
|
|||
# for third party apps
|
||||
def fedibird_capabilities
|
||||
capabilities = [
|
||||
:emoji_reaction,
|
||||
:kmyblue_visibility_public_unlisted,
|
||||
:enable_wide_emoji,
|
||||
:enable_wide_emoji_reaction,
|
||||
|
@ -135,6 +134,7 @@ class REST::V1::InstanceSerializer < ActiveModel::Serializer
|
|||
]
|
||||
|
||||
capabilities << :profile_search unless Chewy.enabled?
|
||||
capabilities << :emoji_reaction if Setting.enable_emoji_reaction
|
||||
|
||||
capabilities
|
||||
end
|
||||
|
|
|
@ -46,8 +46,10 @@ class EmojiReactService < BaseService
|
|||
status = emoji_reaction.status
|
||||
|
||||
if status.account.local?
|
||||
LocalNotificationWorker.perform_async(status.account_id, emoji_reaction.id, 'EmojiReaction', 'reaction') if status.account.user&.setting_emoji_reaction_streaming_notify_impl2
|
||||
LocalNotificationWorker.perform_async(status.account_id, emoji_reaction.id, 'EmojiReaction', 'emoji_reaction')
|
||||
if status.account.user&.setting_enable_emoji_reaction
|
||||
LocalNotificationWorker.perform_async(status.account_id, emoji_reaction.id, 'EmojiReaction', 'reaction') if status.account.user&.setting_emoji_reaction_streaming_notify_impl2
|
||||
LocalNotificationWorker.perform_async(status.account_id, emoji_reaction.id, 'EmojiReaction', 'emoji_reaction')
|
||||
end
|
||||
elsif status.account.activitypub?
|
||||
ActivityPub::DeliveryWorker.perform_async(build_json(emoji_reaction), emoji_reaction.account_id, status.account.inbox_url)
|
||||
end
|
||||
|
@ -63,7 +65,7 @@ class EmojiReactService < BaseService
|
|||
end
|
||||
|
||||
def write_stream(emoji_reaction)
|
||||
emoji_group = emoji_reaction.status.emoji_reactions_grouped_by_name
|
||||
emoji_group = emoji_reaction.status.emoji_reactions_grouped_by_name(nil, force: true)
|
||||
.find { |reaction_group| reaction_group['name'] == emoji_reaction.name && (!reaction_group.key?(:domain) || reaction_group['domain'] == emoji_reaction.custom_emoji&.domain) }
|
||||
emoji_group['status_id'] = emoji_reaction.status_id.to_s
|
||||
DeliveryEmojiReactionWorker.perform_async(render_emoji_reaction(emoji_group), emoji_reaction.status_id, emoji_reaction.account_id)
|
||||
|
|
|
@ -9,7 +9,6 @@ class NotifyService < BaseService
|
|||
update
|
||||
poll
|
||||
emoji_reaction
|
||||
status
|
||||
warning
|
||||
).freeze
|
||||
|
||||
|
@ -53,18 +52,6 @@ class NotifyService < BaseService
|
|||
@recipient.user.settings['interactions.must_be_following'] && !following_sender?
|
||||
end
|
||||
|
||||
def optional_non_follower_emoji_reaction?
|
||||
emoji_reaction? && @recipient.user.settings['emoji_reactions.must_be_follower'] && !@notification.from_account.following?(@recipient)
|
||||
end
|
||||
|
||||
def optional_non_following_emoji_reaction?
|
||||
emoji_reaction? && @recipient.user.settings['emoji_reactions.must_be_following'] && !following_sender?
|
||||
end
|
||||
|
||||
def emoji_reaction?
|
||||
@notification.type == :emoji_reaction
|
||||
end
|
||||
|
||||
def message?
|
||||
@notification.type == :mention
|
||||
end
|
||||
|
@ -134,8 +121,6 @@ class NotifyService < BaseService
|
|||
blocked ||= optional_non_follower?
|
||||
blocked ||= optional_non_following?
|
||||
blocked ||= optional_non_following_and_direct?
|
||||
blocked ||= optional_non_follower_emoji_reaction?
|
||||
blocked ||= optional_non_following_emoji_reaction?
|
||||
blocked ||= conversation_muted?
|
||||
blocked ||= blocked_mention? if @notification.type == :mention
|
||||
blocked
|
||||
|
|
|
@ -11,7 +11,7 @@ class SearchService < BaseService
|
|||
@offset = options[:type].blank? ? 0 : options[:offset].to_i
|
||||
@resolve = options[:resolve] || false
|
||||
@following = options[:following] || false
|
||||
@searchability = options[:searchability] || 'public'
|
||||
@searchability = options[:searchability] || account&.user&.setting_default_searchability_of_search.to_s || 'public'
|
||||
|
||||
default_results.tap do |results|
|
||||
next if @query.blank? || @limit.zero?
|
||||
|
|
|
@ -22,22 +22,6 @@ class EmojiReactionValidator < ActiveModel::Validator
|
|||
end
|
||||
|
||||
def deny_emoji_reactions?(emoji_reaction)
|
||||
return false unless Setting.enable_block_emoji_reaction_settings
|
||||
return false if emoji_reaction.status.account.user.nil?
|
||||
return false if emoji_reaction.status.account_id == emoji_reaction.account_id
|
||||
|
||||
deny_from_all?(emoji_reaction) || non_follower?(emoji_reaction) || non_following?(emoji_reaction)
|
||||
end
|
||||
|
||||
def deny_from_all?(emoji_reaction)
|
||||
emoji_reaction.status.account.user.settings['emoji_reactions.deny_from_all']
|
||||
end
|
||||
|
||||
def non_following?(emoji_reaction)
|
||||
emoji_reaction.status.account.user.settings['emoji_reactions.must_be_following'] && !emoji_reaction.status.account.following?(emoji_reaction.account)
|
||||
end
|
||||
|
||||
def non_follower?(emoji_reaction)
|
||||
emoji_reaction.status.account.user.settings['emoji_reactions.must_be_follower'] && !emoji_reaction.account.following?(emoji_reaction.status.account)
|
||||
!emoji_reaction.status.account.allow_emoji_reaction?(emoji_reaction.account)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
.fields-group
|
||||
= f.input :post_hash_tags_max, wrapper: :with_label, as: :integer, label: t('admin.ng_words.post_hash_tags_max')
|
||||
|
||||
.fields-group
|
||||
= f.input :enable_block_emoji_reaction_settings, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.enable_block_emoji_reaction_settings')
|
||||
|
||||
.fields-group
|
||||
= f.input :hide_local_users_for_anonymous, wrapper: :with_label, as: :boolean, label: t('admin.ng_words.hide_local_users_for_anonymous')
|
||||
|
||||
|
|
|
@ -29,6 +29,17 @@
|
|||
.fields-group
|
||||
= f.input :noindex, as: :boolean, wrapper: :with_label, label: t('admin.settings.default_noindex.title'), hint: t('admin.settings.default_noindex.desc_html')
|
||||
|
||||
%h4= t('admin.settings.discovery.emoji_reactions')
|
||||
|
||||
.fields-group
|
||||
= f.input :enable_emoji_reaction, as: :boolean, wrapper: :with_label, kmyblue: true, hint: false
|
||||
|
||||
.fields-group
|
||||
= f.input :receive_other_servers_emoji_reaction, as: :boolean, wrapper: :with_label, kmyblue: true
|
||||
|
||||
.fields-group
|
||||
= f.input :streaming_other_servers_emoji_reaction, as: :boolean, wrapper: :with_label, kmyblue: true
|
||||
|
||||
%h4= t('admin.settings.discovery.publish_statistics')
|
||||
|
||||
.fields-group
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
- content_for :heading_actions do
|
||||
= link_to t('antennas.new.title'), new_antenna_path, class: 'button'
|
||||
|
||||
.flash-message.alert
|
||||
%strong= t('antennas.beta')
|
||||
|
||||
- if @antennas.empty?
|
||||
.muted-hint.center-text= t 'antennas.index.empty'
|
||||
- else
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
|
||||
.fields-group
|
||||
= ff.input :'web.hide_recent_emojis', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_hide_recent_emojis'), hint: false
|
||||
- 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')
|
||||
|
||||
.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')
|
||||
|
|
|
@ -42,11 +42,8 @@
|
|||
= ff.input :'interactions.must_be_follower', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_follower')
|
||||
= ff.input :'interactions.must_be_following', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following')
|
||||
= ff.input :'interactions.must_be_following_dm', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following_dm')
|
||||
- if Setting.enable_block_emoji_reaction_settings
|
||||
= ff.input :'emoji_reactions.must_be_follower', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.must_be_follower')
|
||||
= ff.input :'emoji_reactions.must_be_following', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.must_be_following')
|
||||
= ff.input :'emoji_reactions.deny_from_all', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.deny_from_all')
|
||||
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
.fields-group
|
||||
= ff.input :stop_emoji_reaction_streaming, as: :boolean, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stop_emoji_reaction_streaming'), hint: I18n.t('simple_form.hints.defaults.setting_stop_emoji_reaction_streaming')
|
||||
- if Setting.enable_emoji_reaction
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
.fields-group
|
||||
= ff.input :stop_emoji_reaction_streaming, as: :boolean, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stop_emoji_reaction_streaming'), hint: I18n.t('simple_form.hints.defaults.setting_stop_emoji_reaction_streaming')
|
||||
|
|
|
@ -14,33 +14,16 @@
|
|||
%h4= t 'preferences.posting_defaults'
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_privacy')
|
||||
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_reblog_privacy, collection: Status.selectable_reblog_visibilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_reblog_privacy')
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |searchability| safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability')
|
||||
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_language, collection: [nil] + filterable_languages, wrapper: :with_label, label_method: ->(locale) { locale.nil? ? I18n.t('statuses.default_language') : native_locale_name(locale) }, required: false, include_blank: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_language')
|
||||
|
||||
.fields-group
|
||||
= ff.input :stay_privacy, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stay_privacy')
|
||||
|
||||
.fields-group
|
||||
= ff.input :public_post_to_unlisted, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_public_post_to_unlisted'), hint: I18n.t('simple_form.hints.defaults.setting_public_post_to_unlisted')
|
||||
|
||||
.fields-group
|
||||
= ff.input :disallow_unlisted_public_searchability, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_disallow_unlisted_public_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_disallow_unlisted_public_searchability')
|
||||
|
||||
.fields-group
|
||||
= ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive')
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.enable_login_privacy', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_enable_login_privacy'), hint: false
|
||||
- if Setting.enable_emoji_reaction
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :emoji_reaction_policy, kmyblue: true, collection: ['allow', 'outside_only', 'followers_only', 'following_only', 'mutuals_only', 'block'], label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_emoji_reaction_policy_items.#{item}")]) }, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', include_blank: false, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_emoji_reaction_policy'), hint: false, warning_hint: I18n.t('simple_form.hints.defaults.setting_emoji_reaction_policy')
|
||||
|
||||
- if @dtl_enabled
|
||||
|
||||
|
|
49
app/views/settings/preferences/reaching/show.html.haml
Normal file
49
app/views/settings/preferences/reaching/show.html.haml
Normal file
|
@ -0,0 +1,49 @@
|
|||
- content_for :page_title do
|
||||
= t('settings.preferences')
|
||||
|
||||
- content_for :heading_actions do
|
||||
= button_tag t('generic.save_changes'), class: 'button', form: 'edit_preferences'
|
||||
|
||||
= simple_form_for current_user, url: settings_preferences_reaching_path, html: { method: :put, id: 'edit_preferences' } do |f|
|
||||
= render 'shared/error_messages', object: current_user
|
||||
|
||||
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||
|
||||
%h4= t 'preferences.visibility'
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_privacy, collection: Status.selectable_visibilities, wrapper: :with_label, include_blank: false, label_method: ->(visibility) { safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_privacy')
|
||||
|
||||
.fields-group.fields-row__column.fields-row__column-6
|
||||
= ff.input :default_reblog_privacy, collection: Status.selectable_reblog_visibilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), I18n.t("statuses.visibilities.#{visibility}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_reblog_privacy')
|
||||
|
||||
.fields-group
|
||||
= ff.input :stay_privacy, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stay_privacy')
|
||||
|
||||
.fields-group
|
||||
= ff.input :public_post_to_unlisted, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_public_post_to_unlisted'), hint: I18n.t('simple_form.hints.defaults.setting_public_post_to_unlisted')
|
||||
|
||||
.fields-group
|
||||
= ff.input :'web.enable_login_privacy', wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_enable_login_privacy'), hint: false
|
||||
|
||||
%h4= t 'preferences.searchability'
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_searchability, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |searchability| safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability')
|
||||
|
||||
.fields-group
|
||||
= ff.input :disallow_unlisted_public_searchability, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_disallow_unlisted_public_searchability'), hint: I18n.t('simple_form.hints.defaults.setting_disallow_unlisted_public_searchability')
|
||||
|
||||
%h4= t 'preferences.search'
|
||||
|
||||
.fields-row
|
||||
.fields-group.fields-row__column.fields-row__column-12
|
||||
= ff.input :default_searchability_of_search, collection: Status.selectable_searchabilities, wrapper: :with_label, kmyblue: true, include_blank: false, label_method: lambda { |searchability| safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_search_long")], ' - ') }, required: false, hint: false, label: I18n.t('simple_form.labels.defaults.setting_default_searchability_of_search')
|
||||
|
||||
.fields-group
|
||||
= ff.input :use_public_index, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_use_public_index')
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
|
@ -6,12 +6,24 @@ class DeliveryEmojiReactionWorker
|
|||
include Lockable
|
||||
include AccountScope
|
||||
|
||||
def perform(payload_json, status_id, _my_account_id = nil)
|
||||
status = Status.find(status_id.to_i)
|
||||
def perform(payload_json, status_id, reacted_account_id)
|
||||
return unless Setting.enable_emoji_reaction
|
||||
|
||||
status = Status.find(status_id)
|
||||
reacted_account = Account.find(reacted_account_id)
|
||||
|
||||
if status.present?
|
||||
scope_status(status).includes(:user).find_each do |account|
|
||||
redis.publish("timeline:#{account.id}", payload_json) if (account.user.nil? || !account.user&.setting_stop_emoji_reaction_streaming) && redis.exists?("subscribed:timeline:#{account.id}")
|
||||
scope = scope_status(status)
|
||||
|
||||
policy = status.account.emoji_reaction_policy
|
||||
return if policy == :block
|
||||
|
||||
scope.select(:id).merge(policy_scope(status.account, policy)).includes(:user).find_each do |account|
|
||||
next if account.user.present? && (account.user.setting_stop_emoji_reaction_streaming || !account.user.setting_enable_emoji_reaction)
|
||||
next unless redis.exists?("subscribed:timeline:#{account.id}")
|
||||
next if !reacted_account.local? && account.excluded_from_timeline_domains.include?(reacted_account.domain)
|
||||
|
||||
redis.publish("timeline:#{account.id}", payload_json)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -19,4 +31,21 @@ class DeliveryEmojiReactionWorker
|
|||
rescue ActiveRecord::RecordNotFound
|
||||
true
|
||||
end
|
||||
|
||||
def policy_scope(account, policy)
|
||||
case policy
|
||||
when :block
|
||||
Account.where(id: 0)
|
||||
when :mutuals_only
|
||||
account.mutuals.local.or(Account.where(id: account))
|
||||
when :following_only
|
||||
account.following.local.or(Account.where(id: account))
|
||||
when :followers_only
|
||||
account.followers.local.or(Account.where(id: account))
|
||||
when :outside_only
|
||||
account.followers.local.or(Account.where(id: account.following.local)).or(Account.where(id: account))
|
||||
else
|
||||
Account.local
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue