diff options
Diffstat (limited to 'app')
13 files changed, 38 insertions, 22 deletions
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 69cf65b5a..7182ed0fa 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -232,10 +232,11 @@ export function uploadCompose(files) { return function (dispatch, getState) { const uploadLimit = 4; const media = getState().getIn(['compose', 'media_attachments']); + const pending = getState().getIn(['compose', 'pending_media_attachments']); const progress = new Array(files.length).fill(0); let total = Array.from(files).reduce((a, v) => a + v.size, 0); - if (files.length + media.size > uploadLimit) { + if (files.length + media.size + pending > uploadLimit) { dispatch(showAlert(undefined, messages.uploadErrorLimit)); return; } @@ -262,7 +263,7 @@ export function uploadCompose(files) { dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total)); }, }).then(({ data }) => dispatch(uploadComposeSuccess(data, f))); - }).catch(error => dispatch(uploadComposeFail(error))); + }).catch(error => dispatch(uploadComposeFail(error, true))); }; }; }; @@ -293,10 +294,11 @@ export function changeUploadComposeSuccess(media) { }; }; -export function changeUploadComposeFail(error) { +export function changeUploadComposeFail(error, decrement = false) { return { type: COMPOSE_UPLOAD_CHANGE_FAIL, error: error, + decrement: decrement, skipLoading: true, }; }; diff --git a/app/javascript/flavours/glitch/features/compose/containers/options_container.js b/app/javascript/flavours/glitch/features/compose/containers/options_container.js index df842f3bf..c792aa582 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/options_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/options_container.js @@ -12,11 +12,12 @@ function mapStateToProps (state) { const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']); const poll = state.getIn(['compose', 'poll']); const media = state.getIn(['compose', 'media_attachments']); + const pending_media = state.getIn(['compose', 'pending_media_attachments']); return { acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']).toArray().join(','), resetFileKey: state.getIn(['compose', 'resetFileKey']), hasPoll: !!poll, - allowMedia: !poll && (media ? media.size < 4 && !media.some(item => ['video', 'audio'].includes(item.get('type'))) : true), + allowMedia: !poll && (media ? media.size + pending_media < 4 && !media.some(item => ['video', 'audio'].includes(item.get('type'))) : pending_media < 4), hasMedia: media && !!media.size, allowPoll: !(media && !!media.size), showContentTypeChoice: state.getIn(['local_settings', 'show_content_type_choice']), diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js index 17ce5de3c..ac826de2b 100644 --- a/app/javascript/flavours/glitch/reducers/compose.js +++ b/app/javascript/flavours/glitch/reducers/compose.js @@ -78,6 +78,7 @@ const initialState = ImmutableMap({ is_changing_upload: false, progress: 0, media_attachments: ImmutableList(), + pending_media_attachments: 0, poll: null, suggestion_token: null, suggestions: ImmutableList(), @@ -201,6 +202,7 @@ function appendMedia(state, media, file) { map.set('is_uploading', false); map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('idempotencyKey', uuid()); + map.update('pending_media_attachments', n => n - 1); if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) { map.set('sensitive', true); @@ -423,11 +425,11 @@ export default function compose(state = initialState, action) { case COMPOSE_UPLOAD_CHANGE_FAIL: return state.set('is_changing_upload', false); case COMPOSE_UPLOAD_REQUEST: - return state.set('is_uploading', true); + return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1); case COMPOSE_UPLOAD_SUCCESS: return appendMedia(state, fromJS(action.media), action.file); case COMPOSE_UPLOAD_FAIL: - return state.set('is_uploading', false); + return state.set('is_uploading', false).update('pending_media_attachments', n => action.decrement ? n - 1 : n); case COMPOSE_UPLOAD_UNDO: return removeMedia(state, action.media_id); case COMPOSE_UPLOAD_PROGRESS: diff --git a/app/javascript/flavours/glitch/styles/components/composer.scss b/app/javascript/flavours/glitch/styles/components/composer.scss index 92a29a933..51287f62e 100644 --- a/app/javascript/flavours/glitch/styles/components/composer.scss +++ b/app/javascript/flavours/glitch/styles/components/composer.scss @@ -249,6 +249,7 @@ .compose-form__autosuggest-wrapper, .autosuggest-input { position: relative; + width: 100%; label { .autosuggest-textarea__textarea { diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 8e7906c73..727f02718 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -205,10 +205,11 @@ export function uploadCompose(files) { return function (dispatch, getState) { const uploadLimit = 4; const media = getState().getIn(['compose', 'media_attachments']); + const pending = getState().getIn(['compose', 'pending_media_attachments']); const progress = new Array(files.length).fill(0); let total = Array.from(files).reduce((a, v) => a + v.size, 0); - if (files.length + media.size > uploadLimit) { + if (files.length + media.size + pending > uploadLimit) { dispatch(showAlert(undefined, messages.uploadErrorLimit)); return; } @@ -235,7 +236,7 @@ export function uploadCompose(files) { dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total)); }, }).then(({ data }) => dispatch(uploadComposeSuccess(data, f))); - }).catch(error => dispatch(uploadComposeFail(error))); + }).catch(error => dispatch(uploadComposeFail(error, true))); }; }; }; @@ -266,10 +267,11 @@ export function changeUploadComposeSuccess(media) { }; }; -export function changeUploadComposeFail(error) { +export function changeUploadComposeFail(error, decrement = false) { return { type: COMPOSE_UPLOAD_CHANGE_FAIL, error: error, + decrement: decrement, skipLoading: true, }; }; diff --git a/app/javascript/mastodon/features/compose/components/poll_form.js b/app/javascript/mastodon/features/compose/components/poll_form.js index bdccf9ce7..923f1029f 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.js +++ b/app/javascript/mastodon/features/compose/components/poll_form.js @@ -142,9 +142,7 @@ class PollForm extends ImmutablePureComponent { </ul> <div className='poll__footer'> - {options.size < 5 && ( - <button className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button> - )} + <button disabled={options.size >= 5} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button> <select value={expiresIn} onChange={this.handleSelectDuration}> <option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option> diff --git a/app/javascript/mastodon/features/compose/containers/upload_button_container.js b/app/javascript/mastodon/features/compose/containers/upload_button_container.js index 1471e628b..221b98e31 100644 --- a/app/javascript/mastodon/features/compose/containers/upload_button_container.js +++ b/app/javascript/mastodon/features/compose/containers/upload_button_container.js @@ -3,7 +3,7 @@ import UploadButton from '../components/upload_button'; import { uploadCompose } from '../../../actions/compose'; const mapStateToProps = state => ({ - disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')))), + disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size + state.getIn(['compose', 'pending_media_attachments']) > 3 || state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')))), unavailable: state.getIn(['compose', 'poll']) !== null, resetFileKey: state.getIn(['compose', 'resetFileKey']), }); diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index b5dc81703..4c3342ccc 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -61,6 +61,7 @@ const initialState = ImmutableMap({ is_uploading: false, progress: 0, media_attachments: ImmutableList(), + pending_media_attachments: 0, poll: null, suggestion_token: null, suggestions: ImmutableList(), @@ -114,6 +115,7 @@ function appendMedia(state, media, file) { map.set('is_uploading', false); map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('idempotencyKey', uuid()); + map.update('pending_media_attachments', n => n - 1); if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) { map.set('sensitive', true); @@ -322,11 +324,11 @@ export default function compose(state = initialState, action) { case COMPOSE_UPLOAD_CHANGE_FAIL: return state.set('is_changing_upload', false); case COMPOSE_UPLOAD_REQUEST: - return state.set('is_uploading', true); + return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1); case COMPOSE_UPLOAD_SUCCESS: return appendMedia(state, fromJS(action.media), action.file); case COMPOSE_UPLOAD_FAIL: - return state.set('is_uploading', false); + return state.set('is_uploading', false).update('pending_media_attachments', n => action.decrement ? n - 1 : n); case COMPOSE_UPLOAD_UNDO: return removeMedia(state, action.media_id); case COMPOSE_UPLOAD_PROGRESS: diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a56806dac..732e42a45 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -392,6 +392,7 @@ .autosuggest-input, .spoiler-input { position: relative; + width: 100%; } .spoiler-input { diff --git a/app/presenters/account_relationships_presenter.rb b/app/presenters/account_relationships_presenter.rb index b05673a3d..08614b67c 100644 --- a/app/presenters/account_relationships_presenter.rb +++ b/app/presenters/account_relationships_presenter.rb @@ -6,7 +6,7 @@ class AccountRelationshipsPresenter :endorsed def initialize(account_ids, current_account_id, **options) - @account_ids = account_ids.map { |a| a.is_a?(Account) ? a.id : a } + @account_ids = account_ids.map { |a| a.is_a?(Account) ? a.id : a.to_i } @current_account_id = current_account_id @following = cached[:following].merge(Account.following_map(@uncached_account_ids, @current_account_id)) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 1941c2e2d..dc47804c0 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -8,7 +8,7 @@ class FollowService < BaseService # @param [Account] source_account From which to follow # @param [String, Account] uri User URI to follow in the form of username@domain (or account record) # @param [true, false, nil] reblogs Whether or not to show reblogs, defaults to true - def call(source_account, target_account, reblogs: nil) + def call(source_account, target_account, reblogs: nil, bypass_locked: false) reblogs = true if reblogs.nil? target_account = ResolveAccountService.new.call(target_account, skip_webfinger: true) @@ -30,7 +30,7 @@ class FollowService < BaseService ActivityTracker.increment('activity:interactions') - if target_account.locked? || source_account.silenced? || target_account.activitypub? + if (target_account.locked? && !bypass_locked) || source_account.silenced? || target_account.activitypub? request_follow(source_account, target_account, reblogs: reblogs) elsif target_account.local? direct_follow(source_account, target_account, reblogs: reblogs) diff --git a/app/workers/move_worker.rb b/app/workers/move_worker.rb index 83f7090ee..595730226 100644 --- a/app/workers/move_worker.rb +++ b/app/workers/move_worker.rb @@ -7,7 +7,7 @@ class MoveWorker @source_account = Account.find(source_account_id) @target_account = Account.find(target_account_id) - if @target_account.local? + if @target_account.local? && @source_account.local? rewrite_follows! else queue_follow_unfollows! @@ -21,13 +21,17 @@ class MoveWorker def rewrite_follows! @source_account.passive_relationships .where(account: Account.local) + .where.not(account: @target_account.followers.local) + .where.not(account_id: @target_account.id) .in_batches .update_all(target_account_id: @target_account.id) end def queue_follow_unfollows! + bypass_locked = @target_account.local? + @source_account.followers.local.select(:id).find_in_batches do |accounts| - UnfollowFollowWorker.push_bulk(accounts.map(&:id)) { |follower_id| [follower_id, @source_account.id, @target_account.id] } + UnfollowFollowWorker.push_bulk(accounts.map(&:id)) { |follower_id| [follower_id, @source_account.id, @target_account.id, bypass_locked] } end end end diff --git a/app/workers/unfollow_follow_worker.rb b/app/workers/unfollow_follow_worker.rb index 95549e107..b6e665a41 100644 --- a/app/workers/unfollow_follow_worker.rb +++ b/app/workers/unfollow_follow_worker.rb @@ -5,12 +5,15 @@ class UnfollowFollowWorker sidekiq_options queue: 'pull' - def perform(follower_account_id, old_target_account_id, new_target_account_id) + def perform(follower_account_id, old_target_account_id, new_target_account_id, bypass_locked = false) follower_account = Account.find(follower_account_id) old_target_account = Account.find(old_target_account_id) new_target_account = Account.find(new_target_account_id) - FollowService.new.call(follower_account, new_target_account) + follow = follower_account.active_relationships.find_by(target_account: old_target_account) + reblogs = follow&.show_reblogs? + + FollowService.new.call(follower_account, new_target_account, reblogs: reblogs, bypass_locked: bypass_locked) UnfollowService.new.call(follower_account, old_target_account, skip_unmerge: true) rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError true |