Merge branch 'kb_development' into kb_migration
This commit is contained in:
commit
ed6acbf542
32 changed files with 509 additions and 275 deletions
|
@ -5,7 +5,6 @@ class AntennasController < ApplicationController
|
||||||
|
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_antenna, only: [:edit, :update, :destroy]
|
before_action :set_antenna, only: [:edit, :update, :destroy]
|
||||||
before_action :set_lists, only: [:new, :edit]
|
|
||||||
before_action :set_body_classes
|
before_action :set_body_classes
|
||||||
before_action :set_cache_headers
|
before_action :set_cache_headers
|
||||||
|
|
||||||
|
@ -54,16 +53,12 @@ class AntennasController < ApplicationController
|
||||||
@antenna = current_account.antennas.find(params[:id])
|
@antenna = current_account.antennas.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_lists
|
|
||||||
@lists = current_account.owned_lists
|
|
||||||
end
|
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:antenna).permit(:title, :list, :available, :insert_feeds, :stl, :expires_in, :with_media_only, :ignore_reblog, :keywords_raw, :exclude_keywords_raw, :domains_raw, :exclude_domains_raw, :accounts_raw, :exclude_accounts_raw, :tags_raw, :exclude_tags_raw)
|
params.require(:antenna).permit(:title, :available, :expires_in)
|
||||||
end
|
end
|
||||||
|
|
||||||
def thin_resource_params
|
def thin_resource_params
|
||||||
params.require(:antenna).permit(:title, :list)
|
params.require(:antenna).permit(:title)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_body_classes
|
def set_body_classes
|
||||||
|
|
|
@ -9,7 +9,9 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
|
||||||
def index
|
def index
|
||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -7,7 +7,9 @@ class Api::V1::BookmarksController < Api::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -7,7 +7,9 @@ class Api::V1::EmojiReactionsController < Api::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -7,7 +7,9 @@ class Api::V1::FavouritesController < Api::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -9,7 +9,9 @@ class Api::V1::Statuses::ReferredByStatusesController < Api::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -9,11 +9,13 @@ class Api::V1::Timelines::HomeController < Api::BaseController
|
||||||
with_read_replica do
|
with_read_replica do
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
@relationships = StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
@relationships = StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
||||||
|
@emoji_reactions = EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: @statuses,
|
render json: @statuses,
|
||||||
each_serializer: REST::StatusSerializer,
|
each_serializer: REST::StatusSerializer,
|
||||||
relationships: @relationships,
|
relationships: @relationships,
|
||||||
|
emoji_reaction_permitted_account_ids: @emoji_reactions,
|
||||||
status: account_home_feed.regenerating? ? 206 : 200
|
status: account_home_feed.regenerating? ? 206 : 200
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,9 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
||||||
def show
|
def show
|
||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -8,7 +8,9 @@ class Api::V1::Timelines::TagController < Api::BaseController
|
||||||
def show
|
def show
|
||||||
cache_if_unauthenticated!
|
cache_if_unauthenticated!
|
||||||
@statuses = load_statuses
|
@statuses = load_statuses
|
||||||
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
|
render json: @statuses, each_serializer: REST::StatusSerializer,
|
||||||
|
relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id),
|
||||||
|
emoji_reaction_permitted_account_ids: EmojiReactionAccountsPresenter.new(@statuses, current_user&.account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -585,6 +585,10 @@ class Status extends ImmutablePureComponent {
|
||||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
const expanded = !status.get('hidden')
|
const expanded = !status.get('hidden')
|
||||||
|
|
||||||
|
const withLimited = status.get('visibility_ex') === 'limited' && status.get('limited_scope') ? <span className='status__visibility-icon'><Icon id='get-pocket' title='Limited' /></span> : null;
|
||||||
|
const withReference = status.get('status_references_count') > 0 ? <span className='status__visibility-icon'><Icon id='link' title='Reference' /></span> : null;
|
||||||
|
const withExpiration = status.get('expires_at') ? <span className='status__visibility-icon'><Icon id='clock-o' title='Expiration' /></span> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility_ex')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility_ex')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
||||||
|
@ -596,6 +600,9 @@ class Status extends ImmutablePureComponent {
|
||||||
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
||||||
<div onClick={this.handleClick} className='status__info'>
|
<div onClick={this.handleClick} className='status__info'>
|
||||||
<a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
|
<a href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time' target='_blank' rel='noopener noreferrer'>
|
||||||
|
{withReference}
|
||||||
|
{withExpiration}
|
||||||
|
{withLimited}
|
||||||
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
|
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
|
||||||
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
|
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
|
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
|
||||||
|
|
||||||
import { updateReactionDeck } from 'mastodon/actions/reaction_deck';
|
import { updateReactionDeck } from 'mastodon/actions/reaction_deck';
|
||||||
import Button from 'mastodon/components/button';
|
import Button from 'mastodon/components/button';
|
||||||
|
|
|
@ -35,7 +35,7 @@ class StatusCacheHydrator
|
||||||
payload[:reblog][:bookmarked] = Bookmark.where(account_id: account_id, status_id: @status.reblog_of_id).exists?
|
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][: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][:filtered] = payload[:filtered]
|
||||||
payload[:reblog][:emoji_reactions] = @status.emoji_reactions_grouped_by_name(account)
|
payload[:reblog][:emoji_reactions] = @status.reblog.emoji_reactions_grouped_by_name(account)
|
||||||
|
|
||||||
if payload[:reblog][:poll]
|
if payload[:reblog][:poll]
|
||||||
if @status.reblog.account_id == account_id
|
if @status.reblog.account_id == account_id
|
||||||
|
|
|
@ -92,142 +92,6 @@ class Antenna < ApplicationRecord
|
||||||
context
|
context
|
||||||
end
|
end
|
||||||
|
|
||||||
def list=(list_id)
|
|
||||||
list_id = list_id.to_i if list_id.is_a?(String)
|
|
||||||
if list_id.is_a?(Numeric)
|
|
||||||
self[:list_id] = list_id
|
|
||||||
else
|
|
||||||
self[:list] = list_id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def keywords_raw
|
|
||||||
return '' if keywords.blank?
|
|
||||||
|
|
||||||
keywords.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def keywords_raw=(raw)
|
|
||||||
keywords = raw.split(/\R/).filter { |r| r.present? && r.length >= 2 }.uniq
|
|
||||||
self[:keywords] = keywords
|
|
||||||
self[:any_keywords] = keywords.none?
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_keywords_raw
|
|
||||||
return '' if exclude_keywords.blank?
|
|
||||||
|
|
||||||
exclude_keywords.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_keywords_raw=(raw)
|
|
||||||
exclude_keywords = raw.split(/\R/).filter(&:present?).uniq
|
|
||||||
self[:exclude_keywords] = exclude_keywords
|
|
||||||
end
|
|
||||||
|
|
||||||
def tags_raw
|
|
||||||
antenna_tags.where(exclude: false).map { |tag| tag.tag.name }.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def tags_raw=(raw)
|
|
||||||
return if tags_raw == raw
|
|
||||||
|
|
||||||
tag_names = raw.split(/\R/).filter(&:present?).map { |r| r.start_with?('#') ? r[1..] : r }.uniq
|
|
||||||
|
|
||||||
antenna_tags.where(exclude: false).destroy_all
|
|
||||||
Tag.find_or_create_by_names(tag_names).each do |tag|
|
|
||||||
antenna_tags.create!(tag: tag, exclude: false)
|
|
||||||
end
|
|
||||||
self[:any_tags] = tag_names.none?
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_tags_raw
|
|
||||||
return '' if exclude_tags.blank?
|
|
||||||
|
|
||||||
Tag.where(id: exclude_tags).map(&:name).join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_tags_raw=(raw)
|
|
||||||
return if exclude_tags_raw == raw
|
|
||||||
|
|
||||||
tags = []
|
|
||||||
tag_names = raw.split(/\R/).filter(&:present?).map { |r| r.start_with?('#') ? r[1..] : r }.uniq
|
|
||||||
Tag.find_or_create_by_names(tag_names).each do |tag|
|
|
||||||
tags << tag.id
|
|
||||||
end
|
|
||||||
self[:exclude_tags] = tags
|
|
||||||
end
|
|
||||||
|
|
||||||
def domains_raw
|
|
||||||
antenna_domains.where(exclude: false).map(&:name).join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def domains_raw=(raw)
|
|
||||||
return if domains_raw == raw
|
|
||||||
|
|
||||||
domain_names = raw.split(/\R/).filter(&:present?).uniq
|
|
||||||
|
|
||||||
antenna_domains.where(exclude: false).destroy_all
|
|
||||||
domain_names.each do |domain|
|
|
||||||
antenna_domains.create!(name: domain, exclude: false)
|
|
||||||
end
|
|
||||||
self[:any_domains] = domain_names.none?
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_domains_raw
|
|
||||||
return '' if exclude_domains.blank?
|
|
||||||
|
|
||||||
exclude_domains.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_domains_raw=(raw)
|
|
||||||
return if exclude_domains_raw == raw
|
|
||||||
|
|
||||||
domain_names = raw.split(/\R/).filter(&:present?).uniq
|
|
||||||
self[:exclude_domains] = domain_names
|
|
||||||
end
|
|
||||||
|
|
||||||
def accounts_raw
|
|
||||||
antenna_accounts.where(exclude: false).map(&:account).map { |account| account.domain ? "@#{account.username}@#{account.domain}" : "@#{account.username}" }.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def accounts_raw=(raw)
|
|
||||||
return if accounts_raw == raw
|
|
||||||
|
|
||||||
account_names = raw.split(/\R/).filter(&:present?).map { |r| r.start_with?('@') ? r[1..] : r }.uniq
|
|
||||||
|
|
||||||
hit = false
|
|
||||||
antenna_accounts.where(exclude: false).destroy_all
|
|
||||||
account_names.each do |name|
|
|
||||||
username, domain = name.split('@')
|
|
||||||
account = Account.find_by(username: username, domain: domain)
|
|
||||||
if account.present?
|
|
||||||
antenna_accounts.create!(account: account, exclude: false)
|
|
||||||
hit = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self[:any_accounts] = !hit
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_accounts_raw
|
|
||||||
return '' if exclude_accounts.blank?
|
|
||||||
|
|
||||||
Account.where(id: exclude_accounts).map { |account| account.domain ? "@#{account.username}@#{account.domain}" : "@#{account.username}" }.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def exclude_accounts_raw=(raw)
|
|
||||||
return if exclude_accounts_raw == raw
|
|
||||||
|
|
||||||
account_names = raw.split(/\R/).filter(&:present?).map { |r| r.start_with?('@') ? r[1..] : r }.uniq
|
|
||||||
|
|
||||||
accounts = []
|
|
||||||
account_names.each do |name|
|
|
||||||
username, domain = name.split('@')
|
|
||||||
account = Account.find_by(username: username, domain: domain)
|
|
||||||
accounts << account.id if account.present?
|
|
||||||
end
|
|
||||||
self[:exclude_accounts] = accounts
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_limit
|
def validate_limit
|
||||||
|
|
|
@ -28,7 +28,8 @@ class PublicFeed
|
||||||
scope.merge!(account_filters_scope) if account?
|
scope.merge!(account_filters_scope) if account?
|
||||||
scope.merge!(media_only_scope) if media_only?
|
scope.merge!(media_only_scope) if media_only?
|
||||||
scope.merge!(language_scope) if account&.chosen_languages.present?
|
scope.merge!(language_scope) if account&.chosen_languages.present?
|
||||||
scope.merge!(anonymous_scope) unless account?
|
# scope.merge!(anonymous_scope) unless account?
|
||||||
|
scope = to_anonymous_scope(scope) unless account?
|
||||||
|
|
||||||
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||||
end
|
end
|
||||||
|
@ -105,6 +106,10 @@ class PublicFeed
|
||||||
local_only? ? Status.where(visibility: [:public, :public_unlisted]) : Status.where(visibility: :public)
|
local_only? ? Status.where(visibility: [:public, :public_unlisted]) : Status.where(visibility: :public)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_anonymous_scope(scope)
|
||||||
|
scope.where.not(visibility: :login)
|
||||||
|
end
|
||||||
|
|
||||||
def account_filters_scope
|
def account_filters_scope
|
||||||
Status.not_excluded_by_account(account).tap do |scope|
|
Status.not_excluded_by_account(account).tap do |scope|
|
||||||
scope.merge!(Status.not_domain_blocked_by_account(account)) unless local_only?
|
scope.merge!(Status.not_domain_blocked_by_account(account)) unless local_only?
|
||||||
|
|
|
@ -173,6 +173,8 @@ class Status < ApplicationRecord
|
||||||
:tags,
|
:tags,
|
||||||
:preview_cards,
|
:preview_cards,
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
|
:reference_objects,
|
||||||
|
:scheduled_expiration_status,
|
||||||
account: [:account_stat, user: :role],
|
account: [:account_stat, user: :role],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
reblog: [
|
reblog: [
|
||||||
|
@ -183,6 +185,8 @@ class Status < ApplicationRecord
|
||||||
:conversation,
|
:conversation,
|
||||||
:status_stat,
|
:status_stat,
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
|
:reference_objects,
|
||||||
|
:scheduled_expiration_status,
|
||||||
account: [:account_stat, user: :role],
|
account: [:account_stat, user: :role],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
],
|
],
|
||||||
|
@ -353,21 +357,30 @@ class Status < ApplicationRecord
|
||||||
return [] if account.present? && !self.account.show_emoji_reaction?(account)
|
return [] if account.present? && !self.account.show_emoji_reaction?(account)
|
||||||
return [] if account.nil? && !options[:force] && self.account.emoji_reaction_policy != :allow
|
return [] if account.nil? && !options[:force] && self.account.emoji_reaction_policy != :allow
|
||||||
|
|
||||||
|
permitted_account_ids = options[:permitted_account_ids]
|
||||||
|
|
||||||
(Oj.load(status_stat&.emoji_reactions || '', mode: :strict) || []).tap do |emoji_reactions|
|
(Oj.load(status_stat&.emoji_reactions || '', mode: :strict) || []).tap do |emoji_reactions|
|
||||||
if account.present?
|
if account.present?
|
||||||
remove_emoji_reactions = []
|
public_emoji_reactions = []
|
||||||
|
|
||||||
emoji_reactions.each do |emoji_reaction|
|
emoji_reactions.each do |emoji_reaction|
|
||||||
emoji_reaction['me'] = emoji_reaction['account_ids'].include?(account.id.to_s)
|
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)
|
emoji_reaction['account_ids'] -= account.excluded_from_timeline_account_ids.map(&:to_s)
|
||||||
|
|
||||||
|
accounts = []
|
||||||
|
if permitted_account_ids
|
||||||
|
emoji_reaction['account_ids'] = emoji_reaction['account_ids'] & permitted_account_ids.map(&:to_s)
|
||||||
|
else
|
||||||
accounts = Account.where(id: emoji_reaction['account_ids'], silenced_at: nil, suspended_at: nil)
|
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?
|
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['account_ids'] = accounts.pluck(:id).map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
emoji_reaction['count'] = emoji_reaction['account_ids'].size
|
emoji_reaction['count'] = emoji_reaction['account_ids'].size
|
||||||
remove_emoji_reactions << emoji_reaction if emoji_reaction['count'] <= 0
|
public_emoji_reactions << emoji_reaction if (emoji_reaction['count']).positive?
|
||||||
end
|
end
|
||||||
emoji_reactions - remove_emoji_reactions
|
|
||||||
|
public_emoji_reactions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -459,6 +472,11 @@ class Status < ApplicationRecord
|
||||||
EmojiReaction.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |e, h| h[e.status_id] = true }
|
EmojiReaction.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |e, h| h[e.status_id] = true }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def emoji_reaction_allows_map(status_ids, account_id)
|
||||||
|
my_account = Account.find_by(id: 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 reload_stale_associations!(cached_items)
|
def reload_stale_associations!(cached_items)
|
||||||
account_ids = []
|
account_ids = []
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,16 @@ class StatusReference < ApplicationRecord
|
||||||
has_one :notification, as: :activity, dependent: :destroy
|
has_one :notification, as: :activity, dependent: :destroy
|
||||||
|
|
||||||
validate :validate_status_visibilities
|
validate :validate_status_visibilities
|
||||||
|
after_commit :reset_parent_cache
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def validate_status_visibilities
|
def validate_status_visibilities
|
||||||
raise Mastodon::ValidationError, I18n.t('status_references.errors.invalid_status_visibilities') if [:public, :public_unlisted, :unlisted, :login].exclude?(target_status.visibility.to_sym)
|
raise Mastodon::ValidationError, I18n.t('status_references.errors.invalid_status_visibilities') if [:public, :public_unlisted, :unlisted, :login].exclude?(target_status.visibility.to_sym)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_parent_cache
|
||||||
|
Rails.cache.delete("statuses/#{status_id}")
|
||||||
|
Rails.cache.delete("statuses/#{target_status_id}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,7 +32,8 @@ class TagFeed < PublicFeed
|
||||||
scope.merge!(remote_only_scope) if remote_only? || hide_local_users?
|
scope.merge!(remote_only_scope) if remote_only? || hide_local_users?
|
||||||
scope.merge!(account_filters_scope) if account?
|
scope.merge!(account_filters_scope) if account?
|
||||||
scope.merge!(media_only_scope) if media_only?
|
scope.merge!(media_only_scope) if media_only?
|
||||||
scope.merge!(anonymous_scope) unless account?
|
# scope.merge!(anonymous_scope) unless account?
|
||||||
|
scope = to_anonymous_scope(scope) unless account?
|
||||||
|
|
||||||
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
|
||||||
end
|
end
|
||||||
|
|
22
app/presenters/emoji_reaction_accounts_presenter.rb
Normal file
22
app/presenters/emoji_reaction_accounts_presenter.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class EmojiReactionAccountsPresenter
|
||||||
|
attr_reader :permitted_account_ids
|
||||||
|
|
||||||
|
def initialize(statuses, current_account_id = nil, **_options)
|
||||||
|
@current_account_id = current_account_id
|
||||||
|
|
||||||
|
statuses = statuses.compact
|
||||||
|
status_ids = statuses.flat_map { |s| [s.id, s.reblog_of_id] }.uniq.compact
|
||||||
|
emoji_reactions = EmojiReaction.where(status_id: status_ids)
|
||||||
|
account_ids = emoji_reactions.pluck(:account_id).uniq
|
||||||
|
|
||||||
|
permitted_accounts = Account.where(id: account_ids, silenced_at: nil, suspended_at: nil)
|
||||||
|
if current_account_id.present?
|
||||||
|
account = Account.find(current_account_id)
|
||||||
|
permitted_accounts = permitted_accounts.where('domain IS NULL OR domain NOT IN (?)', account.excluded_from_timeline_domains) if account.present? && account.excluded_from_timeline_domains.size.positive?
|
||||||
|
end
|
||||||
|
|
||||||
|
@permitted_account_ids = permitted_accounts.pluck(:id)
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,7 +4,7 @@ class StatusRelationshipsPresenter
|
||||||
PINNABLE_VISIBILITIES = %w(public public_unlisted unlisted login private).freeze
|
PINNABLE_VISIBILITIES = %w(public public_unlisted unlisted login private).freeze
|
||||||
|
|
||||||
attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map,
|
attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map,
|
||||||
:bookmarks_map, :filters_map, :emoji_reactions_map, :attributes_map
|
:bookmarks_map, :filters_map, :emoji_reactions_map, :attributes_map, :emoji_reaction_allows_map
|
||||||
|
|
||||||
def initialize(statuses, current_account_id = nil, **options)
|
def initialize(statuses, current_account_id = nil, **options)
|
||||||
@current_account_id = current_account_id
|
@current_account_id = current_account_id
|
||||||
|
@ -17,6 +17,7 @@ class StatusRelationshipsPresenter
|
||||||
@pins_map = {}
|
@pins_map = {}
|
||||||
@filters_map = {}
|
@filters_map = {}
|
||||||
@emoji_reactions_map = {}
|
@emoji_reactions_map = {}
|
||||||
|
@emoji_reaction_allows_map = nil
|
||||||
else
|
else
|
||||||
statuses = statuses.compact
|
statuses = statuses.compact
|
||||||
status_ids = statuses.flat_map { |s| [s.id, s.reblog_of_id] }.uniq.compact
|
status_ids = statuses.flat_map { |s| [s.id, s.reblog_of_id] }.uniq.compact
|
||||||
|
@ -30,6 +31,7 @@ class StatusRelationshipsPresenter
|
||||||
@mutes_map = Status.mutes_map(conversation_ids, current_account_id).merge(options[:mutes_map] || {})
|
@mutes_map = Status.mutes_map(conversation_ids, current_account_id).merge(options[:mutes_map] || {})
|
||||||
@pins_map = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {})
|
@pins_map = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {})
|
||||||
@emoji_reactions_map = Status.emoji_reactions_map(status_ids, current_account_id).merge(options[:emoji_reactions_map] || {})
|
@emoji_reactions_map = Status.emoji_reactions_map(status_ids, current_account_id).merge(options[:emoji_reactions_map] || {})
|
||||||
|
@emoji_reaction_allows_map = Status.emoji_reaction_allows_map(status_ids, current_account_id).merge(options[:emoji_reaction_allows_map] || {})
|
||||||
@attributes_map = options[:attributes_map] || {}
|
@attributes_map = options[:attributes_map] || {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
attribute :bookmarked, if: :current_user?
|
attribute :bookmarked, if: :current_user?
|
||||||
attribute :pinned, if: :pinnable?
|
attribute :pinned, if: :pinnable?
|
||||||
attribute :reactions, if: :reactions?
|
attribute :reactions, if: :reactions?
|
||||||
|
attribute :expires_at, if: :will_expire?
|
||||||
has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user?
|
has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user?
|
||||||
|
|
||||||
attribute :content, unless: :source_requested?
|
attribute :content, unless: :source_requested?
|
||||||
|
@ -122,7 +123,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def emoji_reactions
|
def emoji_reactions
|
||||||
object.emoji_reactions_grouped_by_name(current_user&.account)
|
show_emoji_reaction? ? object.emoji_reactions_grouped_by_name(current_user&.account, permitted_account_ids: emoji_reaction_permitted_account_ids) : []
|
||||||
end
|
end
|
||||||
|
|
||||||
def emoji_reactions_count
|
def emoji_reactions_count
|
||||||
|
@ -131,7 +132,17 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
object.account.emoji_reaction_policy == :allow ? object.emoji_reactions_count : 0
|
object.account.emoji_reaction_policy == :allow ? object.emoji_reactions_count : 0
|
||||||
else
|
else
|
||||||
object.account.show_emoji_reaction?(current_user.account) ? object.emoji_reactions_count : 0
|
show_emoji_reaction? ? object.emoji_reactions_count : 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_emoji_reaction?
|
||||||
|
if relationships
|
||||||
|
return true if relationships.emoji_reaction_allows_map.nil?
|
||||||
|
|
||||||
|
relationships.emoji_reaction_allows_map[object.account_id] || false
|
||||||
|
else
|
||||||
|
object.account.show_emoji_reaction?(current_user.account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -205,12 +216,24 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
object.active_mentions.to_a.sort_by(&:id)
|
object.active_mentions.to_a.sort_by(&:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def will_expire?
|
||||||
|
object.scheduled_expiration_status.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def expires_at
|
||||||
|
object.scheduled_expiration_status.scheduled_at
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def relationships
|
def relationships
|
||||||
instance_options && instance_options[:relationships]
|
instance_options && instance_options[:relationships]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def emoji_reaction_permitted_account_ids
|
||||||
|
current_user.present? && instance_options && instance_options[:emoji_reaction_permitted_account_ids]&.permitted_account_ids
|
||||||
|
end
|
||||||
|
|
||||||
class ApplicationSerializer < ActiveModel::Serializer
|
class ApplicationSerializer < ActiveModel::Serializer
|
||||||
attributes :name, :website
|
attributes :name, :website
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,14 @@ class ProcessReferencesService < BaseService
|
||||||
|
|
||||||
DOMAIN = ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
|
DOMAIN = ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
|
||||||
REFURL_EXP = /(RT|QT|BT|RN|RE)((:|;)?\s+|:|;)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
|
REFURL_EXP = /(RT|QT|BT|RN|RE)((:|;)?\s+|:|;)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
|
||||||
|
MAX_REFERENCES = 5
|
||||||
|
|
||||||
def call(status, reference_parameters, urls: nil)
|
def call(status, reference_parameters, urls: nil)
|
||||||
@status = status
|
@status = status
|
||||||
@reference_parameters = reference_parameters || []
|
@reference_parameters = reference_parameters || []
|
||||||
@urls = urls || []
|
@urls = urls || []
|
||||||
|
|
||||||
old_references
|
@references_count = old_references.size
|
||||||
|
|
||||||
return unless added_references.size.positive? || removed_references.size.positive?
|
return unless added_references.size.positive? || removed_references.size.positive?
|
||||||
|
|
||||||
|
@ -63,6 +64,9 @@ class ProcessReferencesService < BaseService
|
||||||
statuses.each do |status|
|
statuses.each do |status|
|
||||||
@added_objects << @status.reference_objects.new(target_status: status)
|
@added_objects << @status.reference_objects.new(target_status: status)
|
||||||
status.increment_count!(:status_referred_by_count)
|
status.increment_count!(:status_referred_by_count)
|
||||||
|
@references_count += 1
|
||||||
|
|
||||||
|
break if @references_count >= MAX_REFERENCES
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,6 +89,7 @@ class ProcessReferencesService < BaseService
|
||||||
@status.reference_objects.where(target_status: statuses).destroy_all
|
@status.reference_objects.where(target_status: statuses).destroy_all
|
||||||
statuses.each do |status|
|
statuses.each do |status|
|
||||||
status.decrement_count!(:status_referred_by_count)
|
status.decrement_count!(:status_referred_by_count)
|
||||||
|
@references_count -= 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,57 +8,4 @@
|
||||||
= f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t("invites.expires_in.#{i}") }, include_blank: I18n.t('invites.expires_in_prompt')
|
= f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t("invites.expires_in.#{i}") }, include_blank: I18n.t('invites.expires_in_prompt')
|
||||||
|
|
||||||
.fields-row
|
.fields-row
|
||||||
.fields-group.fields-row__column.fields-row__column-6
|
|
||||||
= f.input :list, collection: lists, wrapper: :with_label, label_method: lambda { |list| list.title }, label: t('antennas.edit.list'), selected: f.object.list&.id, hint: false, include_blank: '[Insert to Home]'
|
|
||||||
.fields-group.fields-row__column.fields-row__column-6
|
|
||||||
= f.input :available, wrapper: :with_label, label: t('antennas.edit.available'), hint: false
|
= f.input :available, wrapper: :with_label, label: t('antennas.edit.available'), hint: false
|
||||||
|
|
||||||
.fields-row
|
|
||||||
= f.input :insert_feeds, wrapper: :with_label, label: t('antennas.edit.insert_feeds')
|
|
||||||
.fields-row
|
|
||||||
= f.input :stl, wrapper: :with_label, label: t('antennas.edit.stl'), hint: t('antennas.edit.stl_hint')
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
%p.hint= t 'antennas.edit.hint'
|
|
||||||
%hr.spacer/
|
|
||||||
|
|
||||||
%h4= t('antennas.contexts.domain')
|
|
||||||
%p.hint= t 'antennas.edit.domains_hint'
|
|
||||||
|
|
||||||
.fields-row
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :domains_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.domains_raw')
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :exclude_domains_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.exclude_domains_raw')
|
|
||||||
|
|
||||||
%h4= t('antennas.contexts.account')
|
|
||||||
%p.hint= t 'antennas.edit.accounts_hint'
|
|
||||||
|
|
||||||
.fields-row
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :accounts_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.accounts_raw')
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :exclude_accounts_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.exclude_accounts_raw')
|
|
||||||
|
|
||||||
%h4= t('antennas.contexts.tag')
|
|
||||||
|
|
||||||
.fields-row
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :tags_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.tags_raw')
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :exclude_tags_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.exclude_tags_raw')
|
|
||||||
|
|
||||||
%h4= t('antennas.contexts.keyword')
|
|
||||||
%p.hint= t 'antennas.edit.keywords_hint'
|
|
||||||
|
|
||||||
.fields-row
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :keywords_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.keywords_raw')
|
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
|
||||||
= f.input :exclude_keywords_raw, wrapper: :with_label, as: :text, input_html: { rows: 5 }, label: t('antennas.edit.exclude_keywords_raw')
|
|
||||||
|
|
||||||
%hr.spacer/
|
|
||||||
.fields-group
|
|
||||||
= f.input :with_media_only, wrapper: :with_label, label: t('antennas.edit.with_media_only'), hint: false
|
|
||||||
.fields-group
|
|
||||||
= f.input :ignore_reblog, wrapper: :with_label, label: t('antennas.edit.ignore_reblog'), hint: false
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ class ActivityPub::FetchInstanceInfoWorker
|
||||||
sidekiq_options queue: 'push', retry: 2
|
sidekiq_options queue: 'push', retry: 2
|
||||||
|
|
||||||
class Error < StandardError; end
|
class Error < StandardError; end
|
||||||
class GoneError < Error; end
|
|
||||||
class RequestError < Error; end
|
class RequestError < Error; end
|
||||||
class DeadError < Error; end
|
class DeadError < Error; end
|
||||||
|
|
||||||
|
@ -68,9 +67,7 @@ class ActivityPub::FetchInstanceInfoWorker
|
||||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||||
|
|
||||||
body_to_json(response.body_with_limit)
|
body_to_json(response.body_with_limit)
|
||||||
elsif response.code == 410
|
elsif [400, 401, 403, 404, 410].include?(response.code)
|
||||||
raise ActivityPub::FetchInstanceInfoWorker::GoneError, "#{@instance.domain} is gone from the server"
|
|
||||||
elsif response.code == 404
|
|
||||||
raise ActivityPub::FetchInstanceInfoWorker::DeadError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
raise ActivityPub::FetchInstanceInfoWorker::DeadError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
||||||
else
|
else
|
||||||
raise ActivityPub::FetchInstanceInfoWorker::RequestError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
raise ActivityPub::FetchInstanceInfoWorker::RequestError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
||||||
|
|
|
@ -5,7 +5,7 @@ module Mastodon
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
def kmyblue_major
|
def kmyblue_major
|
||||||
3
|
4
|
||||||
end
|
end
|
||||||
|
|
||||||
def kmyblue_minor
|
def kmyblue_minor
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
"@formatjs/intl-pluralrules": "^5.2.2",
|
"@formatjs/intl-pluralrules": "^5.2.2",
|
||||||
"@gamestdio/websocket": "^0.3.2",
|
"@gamestdio/websocket": "^0.3.2",
|
||||||
"@github/webauthn-json": "^2.1.1",
|
"@github/webauthn-json": "^2.1.1",
|
||||||
|
"@hello-pangea/dnd": "^16.3.0",
|
||||||
"@material-design-icons/svg": "^0.14.10",
|
"@material-design-icons/svg": "^0.14.10",
|
||||||
"@rails/ujs": "^7.0.6",
|
"@rails/ujs": "^7.0.6",
|
||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
|
@ -100,7 +101,6 @@
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"punycode": "^2.3.0",
|
"punycode": "^2.3.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-hotkeys": "^1.1.4",
|
"react-hotkeys": "^1.1.4",
|
||||||
|
|
92
spec/controllers/api/v1/circles/accounts_controller_spec.rb
Normal file
92
spec/controllers/api/v1/circles/accounts_controller_spec.rb
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Api::V1::Circles::AccountsController do
|
||||||
|
render_views
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||||
|
let(:circle) { Fabricate(:circle, account: user.account) }
|
||||||
|
let(:follow) { Fabricate(:follow, target_account: user.account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
circle.accounts << follow.account
|
||||||
|
allow(controller).to receive(:doorkeeper_token) { token }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET #index' do
|
||||||
|
let(:scopes) { 'read:lists' }
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
get :show, params: { circle_id: circle.id }
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST #create' do
|
||||||
|
let(:scopes) { 'write:lists' }
|
||||||
|
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||||
|
|
||||||
|
context 'when the added account is followed' do
|
||||||
|
before do
|
||||||
|
bob.follow!(user.account)
|
||||||
|
post :create, params: { circle_id: circle.id, account_ids: [bob.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds account to the circle' do
|
||||||
|
expect(circle.accounts.include?(bob)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the added account has been sent a follow request' do
|
||||||
|
before do
|
||||||
|
bob.follow_requests.create!(target_account: user.account)
|
||||||
|
post :create, params: { circle_id: circle.id, account_ids: [bob.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds account to the circle' do
|
||||||
|
expect(circle.accounts.include?(bob)).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the added account is not followed' do
|
||||||
|
before do
|
||||||
|
post :create, params: { circle_id: circle.id, account_ids: [bob.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http not found' do
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not add the account to the circle' do
|
||||||
|
expect(circle.accounts.include?(bob)).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE #destroy' do
|
||||||
|
let(:scopes) { 'write:lists' }
|
||||||
|
|
||||||
|
before do
|
||||||
|
delete :destroy, params: { circle_id: circle.id, account_ids: [circle.accounts.first.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes account from the circle' do
|
||||||
|
expect(circle.accounts.count).to eq 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
50
spec/controllers/api/v1/circles_controller_spec.rb
Normal file
50
spec/controllers/api/v1/circles_controller_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Api::V1::CirclesController do
|
||||||
|
render_views
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:circle) { Fabricate(:circle, account: user.account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(controller).to receive(:doorkeeper_token) { token }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a user context' do
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http success' do
|
||||||
|
get :show, params: { id: circle.id }
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with the wrong user context' do
|
||||||
|
let(:other_user) { Fabricate(:user) }
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: other_user.id, scopes: 'read') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http not found' do
|
||||||
|
get :show, params: { id: circle.id }
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a user context' do
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http unprocessable entity' do
|
||||||
|
get :show, params: { id: circle.id }
|
||||||
|
|
||||||
|
expect(response).to have_http_status(422)
|
||||||
|
expect(response.headers['Link']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
50
spec/controllers/api/v1/lists_controller_spec.rb
Normal file
50
spec/controllers/api/v1/lists_controller_spec.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Api::V1::ListsController do
|
||||||
|
render_views
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:list) { Fabricate(:list, account: user.account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(controller).to receive(:doorkeeper_token) { token }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a user context' do
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http success' do
|
||||||
|
get :show, params: { id: list.id }
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with the wrong user context' do
|
||||||
|
let(:other_user) { Fabricate(:user) }
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: other_user.id, scopes: 'read') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http not found' do
|
||||||
|
get :show, params: { id: list.id }
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a user context' do
|
||||||
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read') }
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http unprocessable entity' do
|
||||||
|
get :show, params: { id: list.id }
|
||||||
|
|
||||||
|
expect(response).to have_http_status(422)
|
||||||
|
expect(response.headers['Link']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -66,5 +66,47 @@ describe TagFeed, type: :service do
|
||||||
results = described_class.new(tag_cats, nil).get(20)
|
results = described_class.new(tag_cats, nil).get(20)
|
||||||
expect(results).to include(status)
|
expect(results).to include(status)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'public_unlisted post returns' do
|
||||||
|
status_tagged_with_cats.update(visibility: :public_unlisted)
|
||||||
|
results = described_class.new(tag_cats, nil).get(20)
|
||||||
|
expect(results).to include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'unlisted post not returns' do
|
||||||
|
status_tagged_with_cats.update(visibility: :unlisted)
|
||||||
|
results = described_class.new(tag_cats, nil).get(20)
|
||||||
|
expect(results).to_not include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'unlisted post not returns with account' do
|
||||||
|
status_tagged_with_cats.update(visibility: :unlisted)
|
||||||
|
results = described_class.new(tag_cats, account).get(20)
|
||||||
|
expect(results).to_not include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'unlisted/public_searchability post returns' do
|
||||||
|
status_tagged_with_cats.update(visibility: :unlisted, searchability: :public)
|
||||||
|
results = described_class.new(tag_cats, nil).get(20)
|
||||||
|
expect(results).to include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'unlisted/public_searchability post returns with account' do
|
||||||
|
status_tagged_with_cats.update(visibility: :unlisted, searchability: :public)
|
||||||
|
results = described_class.new(tag_cats, account).get(20)
|
||||||
|
expect(results).to include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'private post not returns' do
|
||||||
|
status_tagged_with_cats.update(visibility: :private, searchability: :public)
|
||||||
|
results = described_class.new(tag_cats, nil).get(20)
|
||||||
|
expect(results).to_not include status_tagged_with_cats
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'private post not returns with account' do
|
||||||
|
status_tagged_with_cats.update(visibility: :private, searchability: :public)
|
||||||
|
results = described_class.new(tag_cats, account).get(20)
|
||||||
|
expect(results).to_not include status_tagged_with_cats
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -266,8 +266,8 @@ RSpec.describe DeliveryAntennaService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when multiple antennas insert list with keyword' do
|
context 'when multiple antennas insert list with keyword' do
|
||||||
let!(:antenna) { antenna_with_keyword(bob, 'body', insert_feeds: true, list: list(bob).id) }
|
let!(:antenna) { antenna_with_keyword(bob, 'body', insert_feeds: true, list: list(bob)) }
|
||||||
let!(:empty_antenna) { antenna_with_keyword(tom, 'body', insert_feeds: true, list: list(tom).id) }
|
let!(:empty_antenna) { antenna_with_keyword(tom, 'body', insert_feeds: true, list: list(tom)) }
|
||||||
|
|
||||||
it 'detecting antenna' do
|
it 'detecting antenna' do
|
||||||
expect(antenna_feed_of(antenna)).to include status.id
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
|
|
@ -7,9 +7,10 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
|
|
||||||
let(:last_active_at) { Time.now.utc }
|
let(:last_active_at) { Time.now.utc }
|
||||||
let(:searchability) { 'public' }
|
let(:searchability) { 'public' }
|
||||||
|
let(:dissubscribable) { false }
|
||||||
let(:status) { Fabricate(:status, account: alice, visibility: visibility, searchability: searchability, text: 'Hello @bob #hoge') }
|
let(:status) { Fabricate(:status, account: alice, visibility: visibility, searchability: searchability, text: 'Hello @bob #hoge') }
|
||||||
|
|
||||||
let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at).account }
|
let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { dissubscribable: dissubscribable }).account }
|
||||||
let!(:bob) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'bob' }).account }
|
let!(:bob) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'bob' }).account }
|
||||||
let!(:tom) { Fabricate(:user, current_sign_in_at: last_active_at).account }
|
let!(:tom) { Fabricate(:user, current_sign_in_at: last_active_at).account }
|
||||||
let!(:ohagi) { Fabricate(:user, current_sign_in_at: last_active_at).account }
|
let!(:ohagi) { Fabricate(:user, current_sign_in_at: last_active_at).account }
|
||||||
|
@ -100,6 +101,14 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
expect(antenna_feed_of(antenna)).to include status.id
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is not added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to_not include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with STL antenna' do
|
context 'with STL antenna' do
|
||||||
|
@ -110,6 +119,14 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
expect(antenna_feed_of(antenna)).to include status.id
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with LTL antenna' do
|
context 'with LTL antenna' do
|
||||||
|
@ -120,6 +137,14 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
expect(antenna_feed_of(antenna)).to include status.id
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -238,6 +263,89 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when status is public_unlisted' do
|
||||||
|
let(:visibility) { 'public_unlisted' }
|
||||||
|
|
||||||
|
it 'is added to the home feed of its author' do
|
||||||
|
expect(home_feed_of(alice)).to include status.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is added to the home feed of a follower' do
|
||||||
|
expect(home_feed_of(bob)).to include status.id
|
||||||
|
expect(home_feed_of(tom)).to include status.id
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is broadcast publicly' do
|
||||||
|
expect(redis).to have_received(:publish).with('timeline:hashtag:hoge', anything)
|
||||||
|
expect(redis).to have_received(:publish).with('timeline:public:local', anything)
|
||||||
|
expect(redis).to_not have_received(:publish).with('timeline:public', anything)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with list' do
|
||||||
|
let!(:list) { list_with_account(bob, alice) }
|
||||||
|
let!(:empty_list) { list_with_account(ohagi, bob) }
|
||||||
|
|
||||||
|
it 'is added to the list feed of list follower' do
|
||||||
|
expect(list_feed_of(list)).to include status.id
|
||||||
|
expect(list_feed_of(empty_list)).to_not include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with antenna' do
|
||||||
|
let!(:antenna) { antenna_with_account(bob, alice) }
|
||||||
|
let!(:empty_antenna) { antenna_with_account(tom, bob) }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed of antenna follower' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is not added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to_not include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with STL antenna' do
|
||||||
|
let!(:antenna) { antenna_with_options(bob, stl: true) }
|
||||||
|
let!(:empty_antenna) { antenna_with_options(tom) }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed of antenna follower' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with LTL antenna' do
|
||||||
|
let!(:antenna) { antenna_with_options(bob, ltl: true) }
|
||||||
|
let!(:empty_antenna) { antenna_with_options(tom) }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed of antenna follower' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
expect(antenna_feed_of(empty_antenna)).to_not include status.id
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when dissubscribable is true' do
|
||||||
|
let(:dissubscribable) { true }
|
||||||
|
|
||||||
|
it 'is added to the antenna feed' do
|
||||||
|
expect(antenna_feed_of(antenna)).to include status.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when status is unlisted' do
|
context 'when status is unlisted' do
|
||||||
let(:visibility) { 'unlisted' }
|
let(:visibility) { 'unlisted' }
|
||||||
|
|
||||||
|
@ -255,6 +363,15 @@ RSpec.describe FanOutOnWriteService, type: :service do
|
||||||
expect(redis).to_not have_received(:publish).with('timeline:public', anything)
|
expect(redis).to_not have_received(:publish).with('timeline:public', anything)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with searchability private' do
|
||||||
|
let(:searchability) { 'private' }
|
||||||
|
|
||||||
|
it 'is not broadcast to the hashtag stream' do
|
||||||
|
expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything)
|
||||||
|
expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge:local', anything)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with list' do
|
context 'with list' do
|
||||||
let!(:list) { list_with_account(bob, alice) }
|
let!(:list) { list_with_account(bob, alice) }
|
||||||
let!(:empty_list) { list_with_account(ohagi, bob) }
|
let!(:empty_list) { list_with_account(ohagi, bob) }
|
||||||
|
|
69
yarn.lock
69
yarn.lock
|
@ -1098,7 +1098,7 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.12.0"
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.22.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.22.3", "@babel/runtime@^7.22.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
|
||||||
version "7.22.15"
|
version "7.22.15"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
||||||
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
||||||
|
@ -1458,6 +1458,19 @@
|
||||||
resolved "https://registry.yarnpkg.com/@github/webauthn-json/-/webauthn-json-2.1.1.tgz#648e63fc28050917d2882cc2b27817a88cb420fc"
|
resolved "https://registry.yarnpkg.com/@github/webauthn-json/-/webauthn-json-2.1.1.tgz#648e63fc28050917d2882cc2b27817a88cb420fc"
|
||||||
integrity sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==
|
integrity sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==
|
||||||
|
|
||||||
|
"@hello-pangea/dnd@^16.3.0":
|
||||||
|
version "16.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@hello-pangea/dnd/-/dnd-16.3.0.tgz#3776212f812df4e8e69c42831ec8ab7ff3a087d6"
|
||||||
|
integrity sha512-RYQ/K8shtJoyNPvFWz0gfXIK7HF3P3mL9UZFGMuHB0ljRSXVgMjVFI/FxcZmakMzw6tO7NflWLriwTNBow/4vw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.22.5"
|
||||||
|
css-box-model "^1.2.1"
|
||||||
|
memoize-one "^6.0.0"
|
||||||
|
raf-schd "^4.0.3"
|
||||||
|
react-redux "^8.1.1"
|
||||||
|
redux "^4.2.1"
|
||||||
|
use-memo-one "^1.1.3"
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.11":
|
"@humanwhocodes/config-array@^0.11.11":
|
||||||
version "0.11.11"
|
version "0.11.11"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
|
||||||
|
@ -2190,7 +2203,7 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
|
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
|
||||||
integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
|
integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
|
||||||
|
|
||||||
"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1":
|
"@types/hoist-non-react-statics@^3.3.1":
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||||
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||||
|
@ -2403,16 +2416,6 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
react-overlays "*"
|
react-overlays "*"
|
||||||
|
|
||||||
"@types/react-redux@^7.1.20":
|
|
||||||
version "7.1.25"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.25.tgz#de841631205b24f9dfb4967dd4a7901e048f9a88"
|
|
||||||
integrity sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==
|
|
||||||
dependencies:
|
|
||||||
"@types/hoist-non-react-statics" "^3.3.0"
|
|
||||||
"@types/react" "*"
|
|
||||||
hoist-non-react-statics "^3.3.0"
|
|
||||||
redux "^4.0.0"
|
|
||||||
|
|
||||||
"@types/react-router-dom@^5.3.3":
|
"@types/react-router-dom@^5.3.3":
|
||||||
version "5.3.3"
|
version "5.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83"
|
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83"
|
||||||
|
@ -4456,7 +4459,7 @@ crypto-random-string@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||||
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
|
||||||
|
|
||||||
css-box-model@^1.2.0:
|
css-box-model@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
|
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
|
||||||
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
|
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
|
||||||
|
@ -8368,11 +8371,6 @@ media-typer@0.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
|
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
|
||||||
|
|
||||||
memoize-one@^5.1.1:
|
|
||||||
version "5.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
|
||||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
|
||||||
|
|
||||||
memoize-one@^6.0.0:
|
memoize-one@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
|
||||||
|
@ -9924,7 +9922,7 @@ quick-lru@^5.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
|
||||||
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
|
||||||
|
|
||||||
raf-schd@^4.0.2:
|
raf-schd@^4.0.3:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
|
||||||
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
|
||||||
|
@ -9966,19 +9964,6 @@ raw-body@2.5.1:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
react-beautiful-dnd@^13.1.1:
|
|
||||||
version "13.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2"
|
|
||||||
integrity sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.9.2"
|
|
||||||
css-box-model "^1.2.0"
|
|
||||||
memoize-one "^5.1.1"
|
|
||||||
raf-schd "^4.0.2"
|
|
||||||
react-redux "^7.2.0"
|
|
||||||
redux "^4.0.4"
|
|
||||||
use-memo-one "^1.1.1"
|
|
||||||
|
|
||||||
react-dom@^18.2.0:
|
react-dom@^18.2.0:
|
||||||
version "18.2.0"
|
version "18.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
|
||||||
|
@ -10060,7 +10045,7 @@ react-is@^16.13.1, react-is@^16.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
|
||||||
react-is@^17.0.1, react-is@^17.0.2:
|
react-is@^17.0.1:
|
||||||
version "17.0.2"
|
version "17.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||||
|
@ -10108,19 +10093,7 @@ react-redux-loading-bar@^5.0.4:
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-lifecycles-compat "^3.0.4"
|
react-lifecycles-compat "^3.0.4"
|
||||||
|
|
||||||
react-redux@^7.2.0:
|
react-redux@^8.0.4, react-redux@^8.1.1:
|
||||||
version "7.2.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"
|
|
||||||
integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.15.4"
|
|
||||||
"@types/react-redux" "^7.1.20"
|
|
||||||
hoist-non-react-statics "^3.3.2"
|
|
||||||
loose-envify "^1.4.0"
|
|
||||||
prop-types "^15.7.2"
|
|
||||||
react-is "^17.0.2"
|
|
||||||
|
|
||||||
react-redux@^8.0.4:
|
|
||||||
version "8.1.2"
|
version "8.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188"
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188"
|
||||||
integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==
|
integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==
|
||||||
|
@ -10378,7 +10351,7 @@ redux-thunk@^2.4.2:
|
||||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
|
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
|
||||||
integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
|
integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
|
||||||
|
|
||||||
redux@^4.0.0, redux@^4.0.4, redux@^4.2.1:
|
redux@^4.0.0, redux@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
|
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
|
||||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||||
|
@ -12312,7 +12285,7 @@ use-latest@^1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
use-isomorphic-layout-effect "^1.1.1"
|
use-isomorphic-layout-effect "^1.1.1"
|
||||||
|
|
||||||
use-memo-one@^1.1.1:
|
use-memo-one@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
|
resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99"
|
||||||
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==
|
integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue