Merge commit 'acdd0b33a3183569a2cdb50befdbba58f1e74ae9' into glitch-soc/merge-upstream
This commit is contained in:
commit
55cd5e1ab1
@ -472,9 +472,8 @@ GEM
|
|||||||
nokogiri (1.19.0)
|
nokogiri (1.19.0)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.13)
|
oj (3.16.14)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
ostruct (>= 0.2)
|
|
||||||
omniauth (2.1.4)
|
omniauth (2.1.4)
|
||||||
hashie (>= 3.4.6)
|
hashie (>= 3.4.6)
|
||||||
logger
|
logger
|
||||||
|
|||||||
@ -140,6 +140,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
'hidden',
|
'hidden',
|
||||||
'unread',
|
'unread',
|
||||||
'pictureInPicture',
|
'pictureInPicture',
|
||||||
|
'headerRenderFn',
|
||||||
];
|
];
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -556,7 +557,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
|
|
||||||
const header = this.props.headerRenderFn
|
const header = this.props.headerRenderFn
|
||||||
? this.props.headerRenderFn({ status, account, avatarSize, messages, onHeaderClick: this.handleHeaderClick })
|
? this.props.headerRenderFn({ status, account, avatarSize, messages, onHeaderClick: this.handleHeaderClick, statusProps: this.props })
|
||||||
: (
|
: (
|
||||||
<StatusHeader
|
<StatusHeader
|
||||||
status={status}
|
status={status}
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import { LinkedDisplayName } from '../display_name';
|
|||||||
import { RelativeTimestamp } from '../relative_timestamp';
|
import { RelativeTimestamp } from '../relative_timestamp';
|
||||||
import { VisibilityIcon } from '../visibility_icon';
|
import { VisibilityIcon } from '../visibility_icon';
|
||||||
|
|
||||||
|
import type { StatusProps } from './types';
|
||||||
|
|
||||||
export interface StatusHeaderProps {
|
export interface StatusHeaderProps {
|
||||||
status: Status;
|
status: Status;
|
||||||
account?: Account;
|
account?: Account;
|
||||||
@ -25,7 +27,10 @@ export interface StatusHeaderProps {
|
|||||||
onHeaderClick?: MouseEventHandler<HTMLDivElement>;
|
onHeaderClick?: MouseEventHandler<HTMLDivElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StatusHeaderRenderFn = (args: StatusHeaderProps) => ReactNode;
|
export type StatusHeaderRenderFn = (
|
||||||
|
args: StatusHeaderProps,
|
||||||
|
statusProps?: StatusProps,
|
||||||
|
) => ReactNode;
|
||||||
|
|
||||||
export const StatusHeader: FC<StatusHeaderProps> = ({
|
export const StatusHeader: FC<StatusHeaderProps> = ({
|
||||||
status,
|
status,
|
||||||
|
|||||||
36
app/javascript/mastodon/components/status/types.ts
Normal file
36
app/javascript/mastodon/components/status/types.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type { ComponentClass, MouseEventHandler, ReactNode } from 'react';
|
||||||
|
|
||||||
|
import type { Account } from '@/mastodon/models/account';
|
||||||
|
|
||||||
|
import type { StatusHeaderRenderFn } from './header';
|
||||||
|
|
||||||
|
// Taken from the Status component.
|
||||||
|
export interface StatusProps {
|
||||||
|
account?: Account;
|
||||||
|
children?: ReactNode;
|
||||||
|
previousId?: string;
|
||||||
|
rootId?: string;
|
||||||
|
onClick?: MouseEventHandler<HTMLDivElement>;
|
||||||
|
muted?: boolean;
|
||||||
|
hidden?: boolean;
|
||||||
|
unread?: boolean;
|
||||||
|
showThread?: boolean;
|
||||||
|
showActions?: boolean;
|
||||||
|
isQuotedPost?: boolean;
|
||||||
|
shouldHighlightOnMount?: boolean;
|
||||||
|
getScrollPosition?: () => null | { height: number; top: number };
|
||||||
|
updateScrollBottom?: (snapshot: number) => void;
|
||||||
|
cacheMediaWidth?: (width: number) => void;
|
||||||
|
cachedMediaWidth?: number;
|
||||||
|
scrollKey?: string;
|
||||||
|
skipPrepend?: boolean;
|
||||||
|
avatarSize?: number;
|
||||||
|
unfocusable?: boolean;
|
||||||
|
headerRenderFn?: StatusHeaderRenderFn;
|
||||||
|
contextType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StatusComponent = ComponentClass<
|
||||||
|
StatusProps,
|
||||||
|
{ showMedia?: boolean; showDespiteFilter?: boolean }
|
||||||
|
>;
|
||||||
@ -226,13 +226,15 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
|||||||
const headerRenderFn: StatusHeaderRenderFn = useCallback(
|
const headerRenderFn: StatusHeaderRenderFn = useCallback(
|
||||||
(props) => (
|
(props) => (
|
||||||
<StatusHeader {...props}>
|
<StatusHeader {...props}>
|
||||||
<IconButton
|
{onQuoteCancel && (
|
||||||
onClick={onQuoteCancel}
|
<IconButton
|
||||||
className='status__quote-cancel'
|
onClick={onQuoteCancel}
|
||||||
title={intl.formatMessage(quoteCancelMessage)}
|
className='status__quote-cancel'
|
||||||
icon='cancel-fill'
|
title={intl.formatMessage(quoteCancelMessage)}
|
||||||
iconComponent={CancelFillIcon}
|
icon='cancel-fill'
|
||||||
/>
|
iconComponent={CancelFillIcon}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</StatusHeader>
|
</StatusHeader>
|
||||||
),
|
),
|
||||||
[intl, onQuoteCancel],
|
[intl, onQuoteCancel],
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
class AfterUnallowDomainService < BaseService
|
class AfterUnallowDomainService < BaseService
|
||||||
def call(domain)
|
def call(domain)
|
||||||
Account.where(domain: domain).find_each do |account|
|
return if domain.blank?
|
||||||
|
|
||||||
|
Account.remote.where(domain: domain).find_each do |account|
|
||||||
DeleteAccountService.new.call(account, reserve_username: false)
|
DeleteAccountService.new.call(account, reserve_username: false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -5,9 +5,7 @@ require 'active_support/core_ext/integer/time'
|
|||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
# Settings specified here will take precedence over those in config/application.rb.
|
# Settings specified here will take precedence over those in config/application.rb.
|
||||||
|
|
||||||
# In the development environment your application's code is reloaded any time
|
# Make code changes take effect immediately without server restart.
|
||||||
# it changes. This slows down response time but is perfect for development
|
|
||||||
# since you don't have to restart the web server when you make code changes.
|
|
||||||
config.enable_reloading = true
|
config.enable_reloading = true
|
||||||
|
|
||||||
# Do not eager load code on boot.
|
# Do not eager load code on boot.
|
||||||
@ -22,8 +20,8 @@ Rails.application.configure do
|
|||||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
||||||
config.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
|
config.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
|
||||||
|
|
||||||
# Enable/disable caching. By default caching is disabled.
|
# Enable/disable Action Controller caching. By default Action Controller caching is disabled.
|
||||||
# Run rails dev:cache to toggle caching.
|
# Run rails dev:cache to toggle Action Controller caching.
|
||||||
if Rails.root.join('tmp', 'caching-dev.txt').exist?
|
if Rails.root.join('tmp', 'caching-dev.txt').exist?
|
||||||
config.action_controller.perform_caching = true
|
config.action_controller.perform_caching = true
|
||||||
config.action_controller.enable_fragment_cache_logging = true
|
config.action_controller.enable_fragment_cache_logging = true
|
||||||
@ -34,7 +32,6 @@ Rails.application.configure do
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
config.action_controller.perform_caching = false
|
config.action_controller.perform_caching = false
|
||||||
|
|
||||||
config.cache_store = :null_store
|
config.cache_store = :null_store
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -52,8 +49,7 @@ Rails.application.configure do
|
|||||||
# Don't care if the mailer can't send.
|
# Don't care if the mailer can't send.
|
||||||
config.action_mailer.raise_delivery_errors = false
|
config.action_mailer.raise_delivery_errors = false
|
||||||
|
|
||||||
# Disable caching for Action Mailer templates even if Action Controller
|
# Make template changes take effect immediately.
|
||||||
# caching is enabled.
|
|
||||||
config.action_mailer.perform_caching = false
|
config.action_mailer.perform_caching = false
|
||||||
|
|
||||||
# Print deprecation notices to the Rails logger.
|
# Print deprecation notices to the Rails logger.
|
||||||
|
|||||||
@ -8,26 +8,16 @@ Rails.application.configure do
|
|||||||
# Code is not reloaded between requests.
|
# Code is not reloaded between requests.
|
||||||
config.enable_reloading = false
|
config.enable_reloading = false
|
||||||
|
|
||||||
# Eager load code on boot. This eager loads most of Rails and
|
# Eager load code on boot for better performance and memory savings (ignored by Rake tasks).
|
||||||
# your application in memory, allowing both threaded web servers
|
|
||||||
# and those relying on copy on write to perform better.
|
|
||||||
# Rake tasks automatically ignore this option for performance.
|
|
||||||
config.eager_load = true
|
config.eager_load = true
|
||||||
|
|
||||||
# Full error reports are disabled and caching is turned on.
|
# Full error reports are disabled and caching is turned on.
|
||||||
config.consider_all_requests_local = false
|
config.consider_all_requests_local = false
|
||||||
config.action_controller.perform_caching = true
|
config.action_controller.perform_caching = true
|
||||||
|
|
||||||
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
|
|
||||||
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
|
|
||||||
# config.require_master_key = true
|
|
||||||
|
|
||||||
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||||
config.assets.compile = false
|
config.assets.compile = false
|
||||||
|
|
||||||
# Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
|
|
||||||
# config.public_file_server.enabled = false
|
|
||||||
|
|
||||||
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
||||||
config.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
|
config.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
|
||||||
|
|
||||||
@ -40,11 +30,11 @@ Rails.application.configure do
|
|||||||
config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split(/(?:\s*,\s*|\s+)/).map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present?
|
config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split(/(?:\s*,\s*|\s+)/).map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present?
|
||||||
|
|
||||||
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
|
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
|
||||||
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
|
|
||||||
# config.assume_ssl = true
|
# config.assume_ssl = true
|
||||||
|
|
||||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||||
config.force_ssl = true
|
config.force_ssl = true
|
||||||
|
|
||||||
# Skip http-to-https redirect for the default health check endpoint.
|
# Skip http-to-https redirect for the default health check endpoint.
|
||||||
config.ssl_options = {
|
config.ssl_options = {
|
||||||
redirect: {
|
redirect: {
|
||||||
@ -59,31 +49,16 @@ Rails.application.configure do
|
|||||||
config.log_tags = [:request_id]
|
config.log_tags = [:request_id]
|
||||||
config.logger = ActiveSupport::TaggedLogging.logger($stdout, formatter: config.log_formatter)
|
config.logger = ActiveSupport::TaggedLogging.logger($stdout, formatter: config.log_formatter)
|
||||||
|
|
||||||
# Change to "debug" to log everything (including potentially personally-identifiable information!)
|
# Change to "debug" to log everything (including potentially personally-identifiable information!).
|
||||||
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info')
|
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info')
|
||||||
|
|
||||||
# Use a different cache store in production.
|
# Use a different cache store in production.
|
||||||
config.cache_store = :redis_cache_store, REDIS_CONFIGURATION.cache
|
config.cache_store = :redis_cache_store, REDIS_CONFIGURATION.cache
|
||||||
|
|
||||||
# Use a real queuing backend for Active Job (and separate queues per environment).
|
|
||||||
# config.active_job.queue_adapter = :resque
|
|
||||||
# config.active_job.queue_name_prefix = "mastodon_production"
|
|
||||||
|
|
||||||
# Disable caching for Action Mailer templates even if Action Controller
|
# Disable caching for Action Mailer templates even if Action Controller
|
||||||
# caching is enabled.
|
# caching is enabled.
|
||||||
config.action_mailer.perform_caching = false
|
config.action_mailer.perform_caching = false
|
||||||
|
|
||||||
# Ignore bad email addresses and do not raise email delivery errors.
|
|
||||||
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
|
||||||
# config.action_mailer.raise_delivery_errors = false
|
|
||||||
|
|
||||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
|
||||||
# the I18n.default_locale when a translation cannot be found).
|
|
||||||
# This setting would typically be `true` to use the `I18n.default_locale`.
|
|
||||||
# Some locales are missing translation entries and would have errors:
|
|
||||||
# https://github.com/mastodon/mastodon/pull/24727
|
|
||||||
config.i18n.fallbacks = [:en]
|
|
||||||
|
|
||||||
# Don't log any deprecations.
|
# Don't log any deprecations.
|
||||||
config.active_support.report_deprecations = false
|
config.active_support.report_deprecations = false
|
||||||
|
|
||||||
@ -94,6 +69,13 @@ Rails.application.configure do
|
|||||||
{ key: controller.signature_key_id } if controller.respond_to?(:signed_request?) && controller.signed_request?
|
{ key: controller.signature_key_id } if controller.respond_to?(:signed_request?) && controller.signed_request?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||||
|
# the I18n.default_locale when a translation cannot be found).
|
||||||
|
# This setting would typically be `true` to use the `I18n.default_locale`.
|
||||||
|
# Some locales are missing translation entries and would have errors:
|
||||||
|
# https://github.com/mastodon/mastodon/pull/24727
|
||||||
|
config.i18n.fallbacks = [:en]
|
||||||
|
|
||||||
# Do not dump schema after migrations.
|
# Do not dump schema after migrations.
|
||||||
config.active_record.dump_schema_after_migration = false
|
config.active_record.dump_schema_after_migration = false
|
||||||
config.action_mailer.perform_caching = false
|
config.action_mailer.perform_caching = false
|
||||||
@ -128,6 +110,7 @@ Rails.application.configure do
|
|||||||
# "example.com", # Allow requests from example.com
|
# "example.com", # Allow requests from example.com
|
||||||
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
|
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
|
||||||
# ]
|
# ]
|
||||||
|
#
|
||||||
# Skip DNS rebinding protection for the default health check endpoint.
|
# Skip DNS rebinding protection for the default health check endpoint.
|
||||||
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,73 +3,45 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe DomainValidator do
|
RSpec.describe DomainValidator do
|
||||||
let(:record) { record_class.new }
|
subject { record_class.new }
|
||||||
|
|
||||||
context 'with no options' do
|
context 'with no options' do
|
||||||
let(:record_class) do
|
let(:record_class) do
|
||||||
Class.new do
|
Class.new do
|
||||||
include ActiveModel::Validations
|
include ActiveModel::Validations
|
||||||
|
|
||||||
|
def self.name = 'Record'
|
||||||
|
|
||||||
attr_accessor :domain
|
attr_accessor :domain
|
||||||
|
|
||||||
validates :domain, domain: true
|
validates :domain, domain: true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#validate_each' do
|
context 'with a nil value' do
|
||||||
context 'with a nil value' do
|
it { is_expected.to allow_value(nil).for(:domain) }
|
||||||
it 'does not add errors' do
|
end
|
||||||
record.domain = nil
|
|
||||||
|
|
||||||
expect(record).to be_valid
|
context 'with a valid domain' do
|
||||||
expect(record.errors).to be_empty
|
it { is_expected.to allow_value('host.example').for(:domain) }
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a valid domain' do
|
context 'with a domain that is too long' do
|
||||||
it 'does not add errors' do
|
let(:long_hostname) { "#{'a' * 300}.com" }
|
||||||
record.domain = 'example.com'
|
|
||||||
|
|
||||||
expect(record).to be_valid
|
it { is_expected.to_not allow_value(long_hostname).for(:domain) }
|
||||||
expect(record.errors).to be_empty
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a domain that is too long' do
|
context 'with a domain with an empty segment' do
|
||||||
it 'adds an error' do
|
it { is_expected.to_not allow_value('.example.com').for(:domain) }
|
||||||
record.domain = "#{'a' * 300}.com"
|
end
|
||||||
|
|
||||||
expect(record).to_not be_valid
|
context 'with a domain with an invalid character' do
|
||||||
expect(record.errors.where(:domain)).to_not be_empty
|
it { is_expected.to_not allow_value('*.example.com').for(:domain) }
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a domain with an empty segment' do
|
context 'with a domain that would fail parsing' do
|
||||||
it 'adds an error' do
|
it { is_expected.to_not allow_value('/').for(:domain) }
|
||||||
record.domain = '.example.com'
|
|
||||||
|
|
||||||
expect(record).to_not be_valid
|
|
||||||
expect(record.errors.where(:domain)).to_not be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a domain with an invalid character' do
|
|
||||||
it 'adds an error' do
|
|
||||||
record.domain = '*.example.com'
|
|
||||||
|
|
||||||
expect(record).to_not be_valid
|
|
||||||
expect(record.errors.where(:domain)).to_not be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a domain that would fail parsing' do
|
|
||||||
it 'adds an error' do
|
|
||||||
record.domain = '/'
|
|
||||||
|
|
||||||
expect(record).to_not be_valid
|
|
||||||
expect(record.errors.where(:domain)).to_not be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -78,48 +50,28 @@ RSpec.describe DomainValidator do
|
|||||||
Class.new do
|
Class.new do
|
||||||
include ActiveModel::Validations
|
include ActiveModel::Validations
|
||||||
|
|
||||||
|
def self.name = 'Record'
|
||||||
|
|
||||||
attr_accessor :acct
|
attr_accessor :acct
|
||||||
|
|
||||||
validates :acct, domain: { acct: true }
|
validates :acct, domain: { acct: true }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#validate_each' do
|
context 'with a nil value' do
|
||||||
context 'with a nil value' do
|
it { is_expected.to allow_value(nil).for(:acct) }
|
||||||
it 'does not add errors' do
|
end
|
||||||
record.acct = nil
|
|
||||||
|
|
||||||
expect(record).to be_valid
|
context 'with no domain' do
|
||||||
expect(record.errors).to be_empty
|
it { is_expected.to allow_value('hoge_123').for(:acct) }
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
context 'with no domain' do
|
context 'with a valid domain' do
|
||||||
it 'does not add errors' do
|
it { is_expected.to allow_value('hoge_123@example.com').for(:acct) }
|
||||||
record.acct = 'hoge_123'
|
end
|
||||||
|
|
||||||
expect(record).to be_valid
|
context 'with an invalid domain' do
|
||||||
expect(record.errors).to be_empty
|
it { is_expected.to_not allow_value('hoge_123@.example.com').for(:acct) }
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a valid domain' do
|
|
||||||
it 'does not add errors' do
|
|
||||||
record.acct = 'hoge_123@example.com'
|
|
||||||
|
|
||||||
expect(record).to be_valid
|
|
||||||
expect(record.errors).to be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with an invalid domain' do
|
|
||||||
it 'adds an error' do
|
|
||||||
record.acct = 'hoge_123@.example.com'
|
|
||||||
|
|
||||||
expect(record).to_not be_valid
|
|
||||||
expect(record.errors.where(:acct)).to_not be_empty
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user