mirror of https://github.com/Siphonay/mastodon
Merge commit '49b3d5692e6f217e6506674ad8a623a4ba8d0c5f' into glitch-soc/backports-4.3
This commit is contained in:
commit
b091e531a5
|
@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||
|
||||
const handleLeftNav = useCallback(() => {
|
||||
|
@ -146,8 +151,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
|
||||
|
||||
const handleDismiss = useCallback(() => {
|
||||
|
|
|
@ -14,6 +14,8 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
|||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
||||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||
import { replyCompose } from 'mastodon/actions/compose';
|
||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
|
@ -159,22 +161,26 @@ class Footer extends ImmutablePureComponent {
|
|||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
}
|
||||
|
||||
let reblogTitle = '';
|
||||
let reblogTitle, reblogIconComponent;
|
||||
|
||||
if (status.get('reblogged')) {
|
||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||
} else if (publicStatus) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog);
|
||||
reblogIconComponent = RepeatIcon;
|
||||
} else if (reblogPrivate) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||
reblogIconComponent = RepeatPrivateIcon;
|
||||
} else {
|
||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||
reblogIconComponent = RepeatDisabledIcon;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='picture-in-picture__footer'>
|
||||
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
||||
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
|
||||
</div>
|
||||
|
|
|
@ -35,6 +35,10 @@ body.rtl {
|
|||
direction: rtl;
|
||||
}
|
||||
|
||||
.column-back-button__icon {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
.simple_form select {
|
||||
background: $ui-base-color
|
||||
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>")
|
||||
|
|
|
@ -40,7 +40,7 @@ class ContentSecurityPolicy
|
|||
end
|
||||
|
||||
def cdn_host_value
|
||||
s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host
|
||||
s3_alias_host || s3_cloudfront_host || azure_alias_host || s3_hostname_host || swift_object_url
|
||||
end
|
||||
|
||||
def paperclip_root_url
|
||||
|
@ -76,6 +76,14 @@ class ContentSecurityPolicy
|
|||
host_to_url ENV.fetch('S3_HOSTNAME', nil)
|
||||
end
|
||||
|
||||
def swift_object_url
|
||||
url = ENV.fetch('SWIFT_OBJECT_URL', nil)
|
||||
return if url.blank? || !url.start_with?('https://')
|
||||
|
||||
url += '/' unless url.end_with?('/')
|
||||
url
|
||||
end
|
||||
|
||||
def uri_from_configuration_and_string(host_string)
|
||||
Addressable::URI.parse("#{host_protocol}://#{host_string}").tap do |uri|
|
||||
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
|
||||
|
|
|
@ -18,5 +18,6 @@ class FollowRecommendation < ApplicationRecord
|
|||
belongs_to :account_summary, foreign_key: :account_id, inverse_of: false
|
||||
belongs_to :account
|
||||
|
||||
scope :localized, ->(locale) { joins(:account_summary).merge(AccountSummary.localized(locale)) }
|
||||
scope :unsupressed, -> { where.not(FollowRecommendationSuppression.where(FollowRecommendationSuppression.arel_table[:account_id].eq(arel_table[:account_id])).select(1).arel.exists) }
|
||||
scope :localized, ->(locale) { unsupressed.joins(:account_summary).merge(AccountSummary.localized(locale)) }
|
||||
end
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
- ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
|
||||
|
||||
Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables.
|
||||
Do not change the secrets once they are set, as doing so may cause data loss and other issues that will be difficult or impossible to recover from.
|
||||
MESSAGE
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,17 @@ namespace :db do
|
|||
namespace :encryption do
|
||||
desc 'Generate a set of keys for configuring Active Record encryption in a given environment'
|
||||
task :init do # rubocop:disable Rails/RakeEnvironment
|
||||
if %w(
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
|
||||
).any? { |key| ENV.key?(key) }
|
||||
pastel = Pastel.new
|
||||
puts pastel.red(<<~MSG)
|
||||
WARNING: It looks like encryption secrets have already been set. Please ensure you are not changing secrets for a Mastodon installation that already uses them, as this will cause data loss and other issues that are difficult to recover from.
|
||||
MSG
|
||||
end
|
||||
|
||||
puts <<~MSG
|
||||
Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set:#{' '}
|
||||
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::TagsController do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
before do
|
||||
Fabricate(:tag)
|
||||
|
||||
tag_filter = instance_double(Admin::TagFilter, results: Tag.all)
|
||||
allow(Admin::TagFilter).to receive(:new).and_return(tag_filter)
|
||||
end
|
||||
|
||||
let(:params) { { order: 'newest' } }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:index)
|
||||
|
||||
expect(Admin::TagFilter)
|
||||
.to have_received(:new)
|
||||
.with(hash_including(params))
|
||||
end
|
||||
|
||||
describe 'with filters' do
|
||||
let(:params) { { order: 'newest', name: 'test' } }
|
||||
|
||||
it 'returns http success' do
|
||||
get :index, params: { name: 'test' }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:index)
|
||||
|
||||
expect(Admin::TagFilter)
|
||||
.to have_received(:new)
|
||||
.with(hash_including(params))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let!(:tag) { Fabricate(:tag) }
|
||||
|
||||
before do
|
||||
get :show, params: { id: tag.id }
|
||||
end
|
||||
|
||||
it 'returns status 200' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let!(:tag) { Fabricate(:tag, listable: false) }
|
||||
|
||||
context 'with valid params' do
|
||||
it 'updates the tag' do
|
||||
put :update, params: { id: tag.id, tag: { listable: '1' } }
|
||||
|
||||
expect(response).to redirect_to(admin_tag_path(tag.id))
|
||||
expect(tag.reload).to be_listable
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
it 'does not update the tag' do
|
||||
put :update, params: { id: tag.id, tag: { name: 'cant-change-name' } }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response).to render_template(:show)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Admin Tags' do
|
||||
describe 'Tag interaction' do
|
||||
let!(:tag) { Fabricate(:tag, name: 'test') }
|
||||
|
||||
before { sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
it 'allows tags listing and editing' do
|
||||
visit admin_tags_path
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('admin.tags.title'))
|
||||
|
||||
click_on '#test'
|
||||
|
||||
fill_in display_name_field, with: 'NewTagName'
|
||||
expect { click_on submit_button }
|
||||
.to_not(change { tag.reload.display_name })
|
||||
expect(page)
|
||||
.to have_content(match_error_text)
|
||||
|
||||
fill_in display_name_field, with: 'TEST'
|
||||
expect { click_on submit_button }
|
||||
.to(change { tag.reload.display_name }.to('TEST'))
|
||||
end
|
||||
|
||||
def display_name_field
|
||||
I18n.t('simple_form.labels.defaults.display_name')
|
||||
end
|
||||
|
||||
def match_error_text
|
||||
I18n.t('tags.does_not_match_previous_name')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -50,9 +50,9 @@ function getSentinelConfiguration(env, commonOptions) {
|
|||
return {
|
||||
db: redisDatabase,
|
||||
name: env.REDIS_SENTINEL_MASTER,
|
||||
username: env.REDIS_USERNAME,
|
||||
username: env.REDIS_USER,
|
||||
password: env.REDIS_PASSWORD,
|
||||
sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USERNAME,
|
||||
sentinelUsername: env.REDIS_SENTINEL_USERNAME ?? env.REDIS_USER,
|
||||
sentinelPassword: env.REDIS_SENTINEL_PASSWORD ?? env.REDIS_PASSWORD,
|
||||
sentinels,
|
||||
...commonOptions,
|
||||
|
@ -104,7 +104,7 @@ export function configFromEnv(env) {
|
|||
host: env.REDIS_HOST ?? '127.0.0.1',
|
||||
port: redisPort,
|
||||
db: redisDatabase,
|
||||
username: env.REDIS_USERNAME,
|
||||
username: env.REDIS_USER,
|
||||
password: env.REDIS_PASSWORD,
|
||||
...commonOptions,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue