Merge commit 'e387175fc9a3ebfd72ab45ebfe43ecfabef7b0c3' into glitch-soc/merge-upstream
This commit is contained in:
@@ -13,7 +13,7 @@ class Api::V1::FeaturedTagsController < Api::BaseController
|
||||
end
|
||||
|
||||
def create
|
||||
featured_tag = CreateFeaturedTagService.new.call(current_account, featured_tag_params[:name])
|
||||
featured_tag = CreateFeaturedTagService.new.call(current_account, params.require(:name))
|
||||
render json: featured_tag, serializer: REST::FeaturedTagSerializer
|
||||
end
|
||||
|
||||
@@ -33,6 +33,6 @@ class Api::V1::FeaturedTagsController < Api::BaseController
|
||||
end
|
||||
|
||||
def featured_tag_params
|
||||
params.permit(:name)
|
||||
params.require(:name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ import api from 'mastodon/api';
|
||||
import { FormattedNumber } from 'react-intl';
|
||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||
import classNames from 'classnames';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
const percIncrease = (a, b) => {
|
||||
let percent;
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import api from 'mastodon/api';
|
||||
import { FormattedNumber } from 'react-intl';
|
||||
import { roundTo10 } from 'mastodon/utils/numbers';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
export default class Dimension extends React.PureComponent {
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { List } from 'immutable';
|
||||
import type { Account } from '../../types/resources';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
|
||||
import Skeleton from './skeleton';
|
||||
import { Skeleton } from './skeleton';
|
||||
|
||||
interface Props {
|
||||
account?: Account;
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
interface Props {
|
||||
size?: number;
|
||||
|
||||
@@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ShortNumber from 'mastodon/components/short_number';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import classNames from 'classnames';
|
||||
|
||||
class SilentErrorBoundary extends React.Component {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import { fetchServer } from 'mastodon/actions/server';
|
||||
import ShortNumber from 'mastodon/components/short_number';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import Account from 'mastodon/containers/account_container';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Skeleton = ({ width, height }) => <span className='skeleton' style={{ width, height }}>‌</span>;
|
||||
|
||||
Skeleton.propTypes = {
|
||||
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
};
|
||||
|
||||
export default Skeleton;
|
||||
12
app/javascript/mastodon/components/skeleton.tsx
Normal file
12
app/javascript/mastodon/components/skeleton.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
}
|
||||
|
||||
export const Skeleton: React.FC<Props> = ({ width, height }) => (
|
||||
<span className='skeleton' style={{ width, height }}>
|
||||
‌
|
||||
</span>
|
||||
);
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
const TimelineHint = ({ resource, url }) => (
|
||||
<div className='timeline-hint'>
|
||||
<strong><FormattedMessage id='timeline_hint.remote_resource_not_displayed' defaultMessage='{resource} from other servers are not displayed.' values={{ resource }} /></strong>
|
||||
<br />
|
||||
<a href={url} target='_blank' rel='noopener'><FormattedMessage id='account.browse_more_on_origin_server' defaultMessage='Browse more on the original profile' /></a>
|
||||
</div>
|
||||
);
|
||||
|
||||
TimelineHint.propTypes = {
|
||||
resource: PropTypes.node.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default TimelineHint;
|
||||
27
app/javascript/mastodon/components/timeline_hint.tsx
Normal file
27
app/javascript/mastodon/components/timeline_hint.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
interface Props {
|
||||
resource: JSX.Element;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export const TimelineHint: React.FC<Props> = ({ resource, url }) => (
|
||||
<div className='timeline-hint'>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id='timeline_hint.remote_resource_not_displayed'
|
||||
defaultMessage='{resource} from other servers are not displayed.'
|
||||
values={{ resource }}
|
||||
/>
|
||||
</strong>
|
||||
<br />
|
||||
<a href={url} target='_blank' rel='noopener noreferrer'>
|
||||
<FormattedMessage
|
||||
id='account.browse_more_on_origin_server'
|
||||
defaultMessage='Browse more on the original profile'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
@@ -8,7 +8,7 @@ import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
|
||||
import Account from 'mastodon/containers/account_container';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import classNames from 'classnames';
|
||||
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||
|
||||
@@ -12,7 +12,7 @@ import ColumnBackButton from '../../components/column_back_button';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import TimelineHint from 'mastodon/components/timeline_hint';
|
||||
import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||
import { me } from 'mastodon/initial_state';
|
||||
import LimitedAccountHint from './components/limited_account_hint';
|
||||
import { getAccountHidden } from 'mastodon/selectors';
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { Blurhash } from 'mastodon/components/blurhash';
|
||||
import { accountsCountRenderer } from 'mastodon/components/hashtag';
|
||||
import ShortNumber from 'mastodon/components/short_number';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class Story extends React.PureComponent {
|
||||
|
||||
@@ -17,7 +17,7 @@ import Column from '../ui/components/column';
|
||||
import HeaderContainer from '../account_timeline/containers/header_container';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import TimelineHint from 'mastodon/components/timeline_hint';
|
||||
import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
||||
import { getAccountHidden } from 'mastodon/selectors';
|
||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||
|
||||
@@ -17,7 +17,7 @@ import Column from '../ui/components/column';
|
||||
import HeaderContainer from '../account_timeline/containers/header_container';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import TimelineHint from 'mastodon/components/timeline_hint';
|
||||
import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||
import LimitedAccountHint from '../account_timeline/components/limited_account_hint';
|
||||
import { getAccountHidden } from 'mastodon/selectors';
|
||||
import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Helmet } from 'react-helmet';
|
||||
import { FormattedMessage, FormattedDate, injectIntl, defineMessages } from 'react-intl';
|
||||
import Column from 'mastodon/components/column';
|
||||
import api from 'mastodon/api';
|
||||
import Skeleton from 'mastodon/components/skeleton';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'privacy_policy.title', defaultMessage: 'Privacy Policy' },
|
||||
|
||||
@@ -85,7 +85,7 @@ class EmbedModal extends ImmutablePureComponent {
|
||||
className='embed-modal__iframe'
|
||||
frameBorder='0'
|
||||
ref={this.setIframeRef}
|
||||
sandbox='allow-same-origin'
|
||||
sandbox='allow-scripts allow-same-origin'
|
||||
title='preview'
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -14,9 +14,9 @@ class Admin::Metrics::Dimension
|
||||
}.freeze
|
||||
|
||||
def self.retrieve(dimension_keys, start_at, end_at, limit, params)
|
||||
Array(dimension_keys).map do |key|
|
||||
Array(dimension_keys).filter_map do |key|
|
||||
klass = DIMENSIONS[key.to_sym]
|
||||
klass&.new(start_at, end_at, limit, klass.with_params? ? params.require(key.to_sym) : nil)
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,9 +19,9 @@ class Admin::Metrics::Measure
|
||||
}.freeze
|
||||
|
||||
def self.retrieve(measure_keys, start_at, end_at, params)
|
||||
Array(measure_keys).map do |key|
|
||||
Array(measure_keys).filter_map do |key|
|
||||
klass = MEASURES[key.to_sym]
|
||||
klass&.new(start_at, end_at, klass.with_params? ? params.require(key.to_sym) : nil)
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,7 +64,7 @@ module Extractor
|
||||
end_position = match_data.char_end(1)
|
||||
after = ::Regexp.last_match.post_match
|
||||
|
||||
if %r{\A://}.match?(after)
|
||||
if after.start_with?('://')
|
||||
hash_text.match(/(.+)(https?\Z)/) do |matched|
|
||||
hash_text = matched[1]
|
||||
end_position -= matched[2].codepoint_length
|
||||
|
||||
@@ -213,7 +213,7 @@ class FeedManager
|
||||
timeline_key = key(:home, account.id)
|
||||
timeline_status_ids = redis.zrange(timeline_key, 0, -1)
|
||||
statuses = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a
|
||||
reblogged_ids = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id)
|
||||
reblogged_ids = Status.where(id: statuses.filter_map(&:reblog_of_id), account: target_account).pluck(:id)
|
||||
with_mentions_ids = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id)
|
||||
|
||||
target_statuses = statuses.select do |status|
|
||||
@@ -233,7 +233,7 @@ class FeedManager
|
||||
timeline_key = key(:list, list.id)
|
||||
timeline_status_ids = redis.zrange(timeline_key, 0, -1)
|
||||
statuses = Status.where(id: timeline_status_ids).select(:id, :reblog_of_id, :account_id).to_a
|
||||
reblogged_ids = Status.where(id: statuses.map(&:reblog_of_id).compact, account: target_account).pluck(:id)
|
||||
reblogged_ids = Status.where(id: statuses.filter_map(&:reblog_of_id), account: target_account).pluck(:id)
|
||||
with_mentions_ids = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact, account: target_account).pluck(:status_id)
|
||||
|
||||
target_statuses = statuses.select do |status|
|
||||
@@ -603,9 +603,9 @@ class FeedManager
|
||||
arr
|
||||
end
|
||||
|
||||
crutches[:following] = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:in_reply_to_account_id).compact).pluck(:target_account_id).index_with(true)
|
||||
crutches[:following] = Follow.where(account_id: receiver_id, target_account_id: statuses.filter_map(&:in_reply_to_account_id)).pluck(:target_account_id).index_with(true)
|
||||
crutches[:languages] = Follow.where(account_id: receiver_id, target_account_id: statuses.map(&:account_id)).pluck(:target_account_id, :languages).to_h
|
||||
crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.map { |s| s.account_id if s.reblog? }.compact, show_reblogs: false).pluck(:target_account_id).index_with(true)
|
||||
crutches[:hiding_reblogs] = Follow.where(account_id: receiver_id, target_account_id: statuses.filter_map { |s| s.account_id if s.reblog? }, show_reblogs: false).pluck(:target_account_id).index_with(true)
|
||||
crutches[:blocking] = Block.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true)
|
||||
crutches[:muting] = Mute.where(account_id: receiver_id, target_account_id: check_for_blocks).pluck(:target_account_id).index_with(true)
|
||||
crutches[:domain_blocking] = AccountDomainBlock.where(account_id: receiver_id, domain: statuses.flat_map { |s| [s.account.domain, s.reblog&.account&.domain] }.compact).pluck(:domain).index_with(true)
|
||||
|
||||
@@ -299,11 +299,11 @@ class Account < ApplicationRecord
|
||||
end
|
||||
|
||||
def fields
|
||||
(self[:fields] || []).map do |f|
|
||||
(self[:fields] || []).filter_map do |f|
|
||||
Account::Field.new(self, f)
|
||||
rescue
|
||||
nil
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
def fields_attributes=(attributes)
|
||||
|
||||
@@ -117,12 +117,12 @@ class AccountStatusesCleanupPolicy < ApplicationRecord
|
||||
private
|
||||
|
||||
def update_last_inspected
|
||||
if EXCEPTION_BOOLS.map { |name| attribute_change_to_be_saved(name) }.compact.include?([true, false])
|
||||
if EXCEPTION_BOOLS.filter_map { |name| attribute_change_to_be_saved(name) }.include?([true, false])
|
||||
# Policy has been widened in such a way that any previously-inspected status
|
||||
# may need to be deleted, so we'll have to start again.
|
||||
redis.del("account_cleanup:#{account_id}")
|
||||
end
|
||||
redis.del("account_cleanup:#{account_id}") if EXCEPTION_THRESHOLDS.map { |name| attribute_change_to_be_saved(name) }.compact.any? { |old, new| old.present? && (new.nil? || new > old) }
|
||||
redis.del("account_cleanup:#{account_id}") if EXCEPTION_THRESHOLDS.filter_map { |name| attribute_change_to_be_saved(name) }.any? { |old, new| old.present? && (new.nil? || new > old) }
|
||||
end
|
||||
|
||||
def validate_local_account
|
||||
|
||||
@@ -48,14 +48,14 @@ class AccountSuggestions::SettingSource < AccountSuggestions::Source
|
||||
end
|
||||
|
||||
def setting_to_usernames_and_domains
|
||||
setting.split(',').map do |str|
|
||||
setting.split(',').filter_map do |str|
|
||||
username, domain = str.strip.gsub(/\A@/, '').split('@', 2)
|
||||
domain = nil if TagManager.instance.local_domain?(domain)
|
||||
|
||||
next if username.blank?
|
||||
|
||||
[username.downcase, domain&.downcase]
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
def setting
|
||||
|
||||
@@ -20,7 +20,7 @@ class AccountSuggestions::Source
|
||||
|
||||
map = scope.index_by { |account| to_ordered_list_key(account) }
|
||||
|
||||
ordered_list.map { |ordered_list_key| map[ordered_list_key] }.compact.map do |account|
|
||||
ordered_list.filter_map { |ordered_list_key| map[ordered_list_key] }.map do |account|
|
||||
AccountSuggestions::Suggestion.new(
|
||||
account: account,
|
||||
source: key
|
||||
|
||||
@@ -22,7 +22,7 @@ class FollowRecommendationFilter
|
||||
account_ids = redis.zrevrange("follow_recommendations:#{@language}", 0, -1).map(&:to_i)
|
||||
accounts = Account.where(id: account_ids).index_by(&:id)
|
||||
|
||||
account_ids.map { |id| accounts[id] }.compact
|
||||
account_ids.filter_map { |id| accounts[id] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -114,7 +114,7 @@ class Notification < ApplicationRecord
|
||||
ActiveRecord::Associations::Preloader.new.preload(grouped_notifications, associations)
|
||||
end
|
||||
|
||||
unique_target_statuses = notifications.map(&:target_status).compact.uniq
|
||||
unique_target_statuses = notifications.filter_map(&:target_status).uniq
|
||||
# Call cache_collection in block
|
||||
cached_statuses_by_id = yield(unique_target_statuses).index_by(&:id)
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class UserRole < ApplicationRecord
|
||||
end
|
||||
|
||||
def permissions_as_keys=(value)
|
||||
self.permissions = value.map(&:presence).compact.reduce(Flags::NONE) { |bitmask, privilege| FLAGS.key?(privilege.to_sym) ? (bitmask | FLAGS[privilege.to_sym]) : bitmask }
|
||||
self.permissions = value.filter_map(&:presence).reduce(Flags::NONE) { |bitmask, privilege| FLAGS.key?(privilege.to_sym) ? (bitmask | FLAGS[privilege.to_sym]) : bitmask }
|
||||
end
|
||||
|
||||
def can?(*any_of_privileges)
|
||||
|
||||
@@ -53,7 +53,7 @@ class Webhook < ApplicationRecord
|
||||
end
|
||||
|
||||
def strip_events
|
||||
self.events = events.map { |str| str.strip.presence }.compact if events.present?
|
||||
self.events = events.filter_map { |str| str.strip.presence } if events.present?
|
||||
end
|
||||
|
||||
def generate_secret
|
||||
|
||||
@@ -68,7 +68,7 @@ class ProcessMentionsService < BaseService
|
||||
def assign_mentions!
|
||||
# Make sure we never mention blocked accounts
|
||||
unless @current_mentions.empty?
|
||||
mentioned_domains = @current_mentions.map { |m| m.account.domain }.compact.uniq
|
||||
mentioned_domains = @current_mentions.filter_map { |m| m.account.domain }.uniq
|
||||
blocked_domains = Set.new(mentioned_domains.empty? ? [] : AccountDomainBlock.where(account_id: @status.account_id, domain: mentioned_domains))
|
||||
mentioned_account_ids = @current_mentions.map(&:account_id)
|
||||
blocked_account_ids = Set.new(@status.account.block_relationships.where(target_account_id: mentioned_account_ids).pluck(:target_account_id))
|
||||
|
||||
@@ -4,14 +4,14 @@ class ExistingUsernameValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
return if value.blank?
|
||||
|
||||
usernames_and_domains = value.split(',').map do |str|
|
||||
usernames_and_domains = value.split(',').filter_map do |str|
|
||||
username, domain = str.strip.gsub(/\A@/, '').split('@', 2)
|
||||
domain = nil if TagManager.instance.local_domain?(domain)
|
||||
|
||||
next if username.blank?
|
||||
|
||||
[str, username, domain]
|
||||
end.compact
|
||||
end
|
||||
|
||||
usernames_with_no_accounts = usernames_and_domains.filter_map do |(str, username, domain)|
|
||||
str unless Account.find_remote(username, domain)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
= render 'auth/shared/progress', stage: 'confirm'
|
||||
|
||||
= hidden_field_tag :confirmation_token, params[:confirmation_token]
|
||||
= hidden_field_tag :redirect_to_app, params[:redirect_to_app]
|
||||
|
||||
%p.lead= t('auth.captcha_confirmation.hint_html')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user