Add emoji reaction notification support
This commit is contained in:
parent
dfe1332be6
commit
de951a0ef9
11 changed files with 100 additions and 23 deletions
|
@ -207,7 +207,9 @@ export function emojiReact(status, emoji) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
dispatch(emojiReactRequest(status, emoji));
|
dispatch(emojiReactRequest(status, emoji));
|
||||||
|
|
||||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/emoji_reactions`, { emoji: emoji.custom ? (emoji.name + (emoji.domain || '')) : emoji.native }).then(function () {
|
const api_emoji = typeof emoji !== 'string' ? (emoji.custom ? (emoji.name + (emoji.domain || '')) : emoji.native) : emoji;
|
||||||
|
|
||||||
|
api(getState).post(`/api/v1/statuses/${status.get('id')}/emoji_reactions`, { emoji: api_emoji }).then(function () {
|
||||||
dispatch(emojiReactSuccess(status, emoji));
|
dispatch(emojiReactSuccess(status, emoji));
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
dispatch(emojiReactFail(status, emoji, error));
|
dispatch(emojiReactFail(status, emoji, error));
|
||||||
|
|
|
@ -137,6 +137,7 @@ const excludeTypesFromFilter = filter => {
|
||||||
'follow',
|
'follow',
|
||||||
'follow_request',
|
'follow_request',
|
||||||
'favourite',
|
'favourite',
|
||||||
|
'emoji_reaction',
|
||||||
'reblog',
|
'reblog',
|
||||||
'mention',
|
'mention',
|
||||||
'poll',
|
'poll',
|
||||||
|
|
|
@ -115,6 +115,17 @@ export default class ColumnSettings extends React.PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div role='group' aria-labelledby='notifications-emoji_reaction'>
|
||||||
|
<span id='notifications-emoji_reaction' className='column-settings__section'><FormattedMessage id='notifications.column_settings.emoji_reaction' defaultMessage='Emoji Reactions:' /></span>
|
||||||
|
|
||||||
|
<div className='column-settings__row'>
|
||||||
|
<SettingToggle disabled={browserPermission === 'denied'} prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'emoji_reaction']} onChange={onChange} label={alertStr} />
|
||||||
|
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'emoji_reaction']} onChange={this.onPushChange} label={pushStr} />}
|
||||||
|
<SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'emoji_reaction']} onChange={onChange} label={showStr} />
|
||||||
|
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'emoji_reaction']} onChange={onChange} label={soundStr} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div role='group' aria-labelledby='notifications-mention'>
|
<div role='group' aria-labelledby='notifications-mention'>
|
||||||
<span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
|
<span id='notifications-mention' className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,13 @@ class FilterBar extends React.PureComponent {
|
||||||
>
|
>
|
||||||
<Icon id='star' fixedWidth />
|
<Icon id='star' fixedWidth />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className={selectedFilter === 'emoji_reaction' ? 'active' : ''}
|
||||||
|
onClick={this.onClick('emoji_reaction')}
|
||||||
|
title={intl.formatMessage(tooltips.emojiReactions)}
|
||||||
|
>
|
||||||
|
<Icon id='star' fixedWidth />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className={selectedFilter === 'reblog' ? 'active' : ''}
|
className={selectedFilter === 'reblog' ? 'active' : ''}
|
||||||
onClick={this.onClick('reblog')}
|
onClick={this.onClick('reblog')}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
favourite: { id: 'notification.favourite', defaultMessage: '{name} favourited your status' },
|
favourite: { id: 'notification.favourite', defaultMessage: '{name} favourited your status' },
|
||||||
|
emojiReaction: { id: 'notification.emoji_reaction', defaultMessage: '{name} reacted your status with emoji' },
|
||||||
follow: { id: 'notification.follow', defaultMessage: '{name} followed you' },
|
follow: { id: 'notification.follow', defaultMessage: '{name} followed you' },
|
||||||
ownPoll: { id: 'notification.own_poll', defaultMessage: 'Your poll has ended' },
|
ownPoll: { id: 'notification.own_poll', defaultMessage: 'Your poll has ended' },
|
||||||
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
|
poll: { id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' },
|
||||||
|
@ -213,6 +214,38 @@ class Notification extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderEmojiReaction (notification, link) {
|
||||||
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HotKeys handlers={this.getHandlers()}>
|
||||||
|
<div className={classNames('notification notification-emoji_reaction focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.emojiReaction, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
|
<div className='notification__message'>
|
||||||
|
<div className='notification__emoji_reaction-icon-wrapper'>
|
||||||
|
<Icon id='star' className='star-icon' fixedWidth />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span title={notification.get('created_at')}>
|
||||||
|
<FormattedMessage id='notification.emoji_reaction' defaultMessage='{name} reacted your status with emoji' values={{ name: link }} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<StatusContainer
|
||||||
|
id={notification.get('status')}
|
||||||
|
account={notification.get('account')}
|
||||||
|
muted
|
||||||
|
withDismiss
|
||||||
|
hidden={!!this.props.hidden}
|
||||||
|
getScrollPosition={this.props.getScrollPosition}
|
||||||
|
updateScrollBottom={this.props.updateScrollBottom}
|
||||||
|
cachedMediaWidth={this.props.cachedMediaWidth}
|
||||||
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</HotKeys>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderReblog (notification, link) {
|
renderReblog (notification, link) {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
|
@ -429,6 +462,8 @@ class Notification extends ImmutablePureComponent {
|
||||||
return this.renderMention(notification);
|
return this.renderMention(notification);
|
||||||
case 'favourite':
|
case 'favourite':
|
||||||
return this.renderFavourite(notification, link);
|
return this.renderFavourite(notification, link);
|
||||||
|
case 'emoji_reaction':
|
||||||
|
return this.renderEmojiReaction(notification, link);
|
||||||
case 'reblog':
|
case 'reblog':
|
||||||
return this.renderReblog(notification, link);
|
return this.renderReblog(notification, link);
|
||||||
case 'status':
|
case 'status':
|
||||||
|
|
|
@ -45,11 +45,10 @@ const updateStatusEmojiReaction = (state, emoji_reaction, myId) => {
|
||||||
let emoji_reactions = Array.from(status.get('emoji_reactions') || []);
|
let emoji_reactions = Array.from(status.get('emoji_reactions') || []);
|
||||||
|
|
||||||
if (emoji_reaction.count > 0) {
|
if (emoji_reaction.count > 0) {
|
||||||
const old_emoji = emoji_reactions.find((er) => er.name === emoji_reaction.name && er.url === emoji_reaction.url);
|
const old_emoji = emoji_reactions.find((er) => er.get('name') === emoji_reaction.name && (!er.get('domain') || er.get('domain') === emoji_reaction.domain));
|
||||||
if (old_emoji) {
|
if (old_emoji) {
|
||||||
old_emoji.account_ids = emoji_reaction.account_ids;
|
const index = emoji_reactions.indexOf(old_emoji);
|
||||||
old_emoji.count = emoji_reaction.count;
|
emoji_reactions[index] = old_emoji.merge({ account_ids: emoji_reaction.account_ids, count: emoji_reaction.count, me: emoji_reaction.me });
|
||||||
old_emoji.me = emoji_reaction.me;
|
|
||||||
} else {
|
} else {
|
||||||
emoji_reactions.push(ImmutableMap(emoji_reaction));
|
emoji_reactions.push(ImmutableMap(emoji_reaction));
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Notification < ApplicationRecord
|
||||||
'Follow' => :follow,
|
'Follow' => :follow,
|
||||||
'FollowRequest' => :follow_request,
|
'FollowRequest' => :follow_request,
|
||||||
'Favourite' => :favourite,
|
'Favourite' => :favourite,
|
||||||
|
'EmojiReaction' => :emoji_reaction,
|
||||||
'Poll' => :poll,
|
'Poll' => :poll,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ class Notification < ApplicationRecord
|
||||||
follow
|
follow
|
||||||
follow_request
|
follow_request
|
||||||
favourite
|
favourite
|
||||||
|
emoji_reaction
|
||||||
poll
|
poll
|
||||||
update
|
update
|
||||||
admin.sign_up
|
admin.sign_up
|
||||||
|
@ -46,6 +48,7 @@ class Notification < ApplicationRecord
|
||||||
reblog: [status: :reblog],
|
reblog: [status: :reblog],
|
||||||
mention: [mention: :status],
|
mention: [mention: :status],
|
||||||
favourite: [favourite: :status],
|
favourite: [favourite: :status],
|
||||||
|
emoji_reaction: [emoji_reaction: :status],
|
||||||
poll: [poll: :status],
|
poll: [poll: :status],
|
||||||
update: :status,
|
update: :status,
|
||||||
'admin.report': [report: :target_account],
|
'admin.report': [report: :target_account],
|
||||||
|
|
|
@ -12,7 +12,7 @@ class REST::NotificationSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def status_type?
|
def status_type?
|
||||||
[:favourite, :reblog, :status, :mention, :poll, :update].include?(object.type)
|
[:favourite, :emoji_reaction, :reblog, :status, :mention, :poll, :update].include?(object.type)
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_type?
|
def report_type?
|
||||||
|
|
|
@ -4,14 +4,20 @@ class UnEmojiReactService < BaseService
|
||||||
include Redisable
|
include Redisable
|
||||||
include Payloadable
|
include Payloadable
|
||||||
|
|
||||||
def call(account, status, emoji_reaction = nil)
|
def call(account_id, status_id, emoji_reaction = nil)
|
||||||
|
@account_id = account_id
|
||||||
|
@account = Account.find(account_id)
|
||||||
|
@status = Status.find(status_id)
|
||||||
|
|
||||||
if emoji_reaction
|
if emoji_reaction
|
||||||
|
p '================================ DEBUG2 G'
|
||||||
emoji_reaction.destroy
|
emoji_reaction.destroy
|
||||||
create_notification(emoji_reaction) if !status.account.local? && status.account.activitypub?
|
p '================================ DEBUG2 H'
|
||||||
notify_to_followers(emoji_reaction) if status.account.local?
|
create_notification(emoji_reaction) if !@account.local? && @account.activitypub?
|
||||||
|
notify_to_followers(emoji_reaction) if @account.local?
|
||||||
write_stream(emoji_reaction)
|
write_stream(emoji_reaction)
|
||||||
else
|
else
|
||||||
bulk(account, status)
|
bulk(@account, @status)
|
||||||
end
|
end
|
||||||
emoji_reaction
|
emoji_reaction
|
||||||
end
|
end
|
||||||
|
@ -25,33 +31,31 @@ class UnEmojiReactService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_notification(emoji_reaction)
|
def create_notification(emoji_reaction)
|
||||||
status = emoji_reaction.status
|
ActivityPub::DeliveryWorker.perform_async(build_json(emoji_reaction), @account_id, @account.inbox_url)
|
||||||
ActivityPub::DeliveryWorker.perform_async(build_json(emoji_reaction), status.account_id, status.account.inbox_url)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_to_followers(emoji_reaction)
|
def notify_to_followers(emoji_reaction)
|
||||||
status = emoji_reaction.status
|
ActivityPub::RawDistributionWorker.perform_async(build_json(emoji_reaction), @account_id)
|
||||||
ActivityPub::RawDistributionWorker.perform_async(build_json(emoji_reaction), status.account_id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_stream(emoji_reaction)
|
def write_stream(emoji_reaction)
|
||||||
emoji_group = emoji_reaction.status.emoji_reactions_grouped_by_name
|
emoji_group = @status.emoji_reactions_grouped_by_name
|
||||||
.find { |reaction_group| reaction_group['name'] == emoji_reaction.name && (!reaction_group.key?(:domain) || reaction_group['domain'] == emoji_reaction.domain) }
|
.find { |reaction_group| reaction_group['name'] == emoji_reaction.name && (!reaction_group.key?(:domain) || reaction_group['domain'] == emoji_reaction.domain) }
|
||||||
if emoji_group
|
if emoji_group
|
||||||
emoji_group['status_id'] = emoji_reaction.status_id.to_s
|
emoji_group['status_id'] = @status.id.to_s
|
||||||
else
|
else
|
||||||
# name: emoji_reaction.name, count: 0, domain: emoji_reaction.domain
|
# name: emoji_reaction.name, count: 0, domain: emoji_reaction.domain
|
||||||
emoji_group = { 'name' => emoji_reaction.name, 'count' => 0, 'account_ids' => [], 'status_id' => emoji_reaction.status_id.to_s }
|
emoji_group = { 'name' => emoji_reaction.name, 'count' => 0, 'account_ids' => [], 'status_id' => @status.id.to_s }
|
||||||
emoji_group['domain'] = emoji_reaction.custom_emoji.domain if emoji_reaction.custom_emoji
|
emoji_group['domain'] = emoji_reaction.custom_emoji.domain if emoji_reaction.custom_emoji
|
||||||
end
|
end
|
||||||
FeedAnyJsonWorker.perform_async(render_emoji_reaction(emoji_group), emoji_reaction.status_id, emoji_reaction.account_id)
|
FeedAnyJsonWorker.perform_async(render_emoji_reaction(emoji_group), @status.id, @account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_json(emoji_reaction)
|
def build_json(emoji_reaction)
|
||||||
Oj.dump(serialize_payload(emoji_reaction, ActivityPub::UndoEmojiReactionSerializer))
|
Oj.dump(serialize_payload(emoji_reaction, ActivityPub::UndoEmojiReactionSerializer))
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_emoji_reaction(_emoji_reaction, emoji_group)
|
def render_emoji_reaction(emoji_group)
|
||||||
# @rendered_emoji_reaction ||= InlineRenderer.render(emoji_group, nil, :emoji_reaction)
|
# @rendered_emoji_reaction ||= InlineRenderer.render(emoji_group, nil, :emoji_reaction)
|
||||||
Oj.dump(event: :emoji_reaction, payload: emoji_group.to_json)
|
Oj.dump(event: :emoji_reaction, payload: emoji_group.to_json)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,14 +7,29 @@ class FeedAnyJsonWorker
|
||||||
include AccountLimitable
|
include AccountLimitable
|
||||||
|
|
||||||
def perform(payload_json, status_id, my_account_id = nil)
|
def perform(payload_json, status_id, my_account_id = nil)
|
||||||
|
p '========================================= DEBUG AAA'
|
||||||
redis.publish("timeline:#{my_account_id}", payload_json) if my_account_id.present?
|
redis.publish("timeline:#{my_account_id}", payload_json) if my_account_id.present?
|
||||||
|
p '========================================= DEBUG AA'
|
||||||
|
p status_id
|
||||||
|
p status_id.to_i
|
||||||
|
|
||||||
status = Status.find(status_id.to_i)
|
status = Status.find(status_id.to_i)
|
||||||
|
p '========================================= DEBUG AAAAAAAA'
|
||||||
|
p status.present?
|
||||||
|
|
||||||
if status.present?
|
if status.present?
|
||||||
scope_status(status).find_each do |account_id|
|
p '========================================= DEBUG A'
|
||||||
p account_id if redis.exists?("subscribed:timeline:#{account_id}")
|
p scope_status(status)
|
||||||
redis.publish("timeline:#{account_id}", payload_json) if redis.exists?("subscribed:timeline:#{account_id}")
|
p '========================================= DEBUG C'
|
||||||
|
scope_status(status).find_each do |account|
|
||||||
|
p '========================================= DEBUG D'
|
||||||
|
p redis.exists?("subscribed:timeline:#{account.id}")
|
||||||
|
redis.publish("timeline:#{account.id}", payload_json) if redis.exists?("subscribed:timeline:#{account.id}")
|
||||||
|
end
|
||||||
|
|
||||||
|
if status.visibility.to_sym != :public && status.visibility.to_sym != :unlisted && status.account_id != my_account_id &&
|
||||||
|
redis.exists?("subscribed:timeline:#{status.account_id}")
|
||||||
|
redis.publish("timeline:#{status.account_id}", payload_json)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ class UnEmojiReactWorker
|
||||||
.find { |reaction| domain == '' ? reaction.custom_emoji.nil? : reaction.custom_emoji&.domain == domain }
|
.find { |reaction| domain == '' ? reaction.custom_emoji.nil? : reaction.custom_emoji&.domain == domain }
|
||||||
end
|
end
|
||||||
|
|
||||||
UnEmojiReactService.new.call(Account.find(account_id), Status.find(status_id), emoji_reaction)
|
UnEmojiReactService.new.call(account_id.to_i, status_id.to_i, emoji_reaction)
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue