diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 166193842..e2eab242d 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -14,7 +14,7 @@ import { openModal } from './modal'; import { defineMessages } from 'react-intl'; import { addYears, addMonths, addDays, addHours, addMinutes, addSeconds, millisecondsToSeconds, set, formatISO, format } from 'date-fns'; import { Set as ImmutableSet } from 'immutable'; -import { postReferenceModal, enableFederatedTimeline } from '../initial_state'; +import { postReferenceModal, enableFederatedTimeline, allowPollImage } from '../initial_state'; import { deleteScheduledStatus } from './scheduled_statuses'; let cancelFetchComposeSuggestionsAccounts, cancelFetchComposeSuggestionsTags; @@ -384,7 +384,7 @@ export function uploadCompose(files) { return; } - if (getState().getIn(['compose', 'poll'])) { + if (!allowPollImage && getState().getIn(['compose', 'poll'])) { dispatch(showAlert(undefined, messages.uploadErrorPoll)); return; } diff --git a/app/javascript/mastodon/features/compose/containers/poll_button_container.js b/app/javascript/mastodon/features/compose/containers/poll_button_container.js index 8f1cb7c10..250f344df 100644 --- a/app/javascript/mastodon/features/compose/containers/poll_button_container.js +++ b/app/javascript/mastodon/features/compose/containers/poll_button_container.js @@ -1,9 +1,10 @@ import { connect } from 'react-redux'; import PollButton from '../components/poll_button'; import { addPoll, removePoll } from '../../../actions/compose'; +import { allowPollImage } from '../../../initial_state'; const mapStateToProps = state => ({ - unavailable: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0), + unavailable: !allowPollImage && (state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0)), active: state.getIn(['compose', 'poll']) !== null, }); 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 221b98e31..f6918dc8e 100644 --- a/app/javascript/mastodon/features/compose/containers/upload_button_container.js +++ b/app/javascript/mastodon/features/compose/containers/upload_button_container.js @@ -1,10 +1,11 @@ import { connect } from 'react-redux'; import UploadButton from '../components/upload_button'; import { uploadCompose } from '../../../actions/compose'; +import { allowPollImage } from '../../../initial_state'; const mapStateToProps = state => ({ 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, + unavailable: !allowPollImage && state.getIn(['compose', 'poll']) !== null, resetFileKey: state.getIn(['compose', 'resetFileKey']), }); diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 1af332568..47c679b81 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -75,6 +75,7 @@ export const hidePrivacyMeta = getMeta('hide_privacy_meta'); export const hideLinkPreview = getMeta('hide_link_preview'); export const hidePhotoPreview = getMeta('hide_photo_preview'); export const hideVideoPreview = getMeta('hide_video_preview'); +export const allowPollImage = getMeta('allow_poll_image'); export const maxChars = initialState?.max_toot_chars ?? 500; diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 2029ab726..fd77c2521 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -35,6 +35,7 @@ class Form::AdminSettings show_domain_blocks_rationale noindex require_invite_text + allow_poll_image ).freeze BOOLEAN_KEYS = %i( @@ -51,6 +52,7 @@ class Form::AdminSettings trendable_by_default noindex require_invite_text + allow_poll_image ).freeze UPLOAD_KEYS = %i( diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index 072a995a5..9d54e9eb2 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -23,6 +23,7 @@ class InitialStateSerializer < ActiveModel::Serializer mascot: instance_presenter.mascot&.file&.url, profile_directory: Setting.profile_directory, trends: Setting.trends, + allow_poll_image: Setting.allow_poll_image, } if object.current_account diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 1df7380e3..a572fabbc 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -89,6 +89,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer max_characters_per_option: PollValidator::MAX_OPTION_CHARS, min_expiration: PollValidator::MIN_EXPIRATION, max_expiration: PollValidator::MAX_EXPIRATION, + allow_image: Setting.allow_poll_image, }, emoji_reactions: { diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb index b855ace69..5f675bafc 100644 --- a/app/services/post_status_service.rb +++ b/app/services/post_status_service.rb @@ -176,7 +176,7 @@ class PostStatusService < BaseService def validate_media! return if @options[:media_ids].blank? || !@options[:media_ids].is_a?(Enumerable) - raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 || @options[:poll].present? + raise Mastodon::ValidationError, I18n.t('media_attachments.validations.too_many') if @options[:media_ids].size > 4 || !Setting.allow_poll_image && @options[:poll].present? @media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i)) diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml index 664cd0b5e..68f2db615 100644 --- a/app/views/admin/settings/edit.html.haml +++ b/app/views/admin/settings/edit.html.haml @@ -92,6 +92,9 @@ .fields-group = f.input :noindex, as: :boolean, wrapper: :with_label, label: t('admin.settings.default_noindex.title'), hint: t('admin.settings.default_noindex.desc_html') + .fields-group + = f.input :allow_poll_image, as: :boolean, wrapper: :with_label, label: t('admin.settings.allow_poll_image.title'), hint: t('admin.settings.allow_poll_image.desc_html'), fedibird_features: true + %hr.spacer/ .fields-group diff --git a/config/locales/en.yml b/config/locales/en.yml index bff4bcb7f..4a78d4c9c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -627,6 +627,9 @@ en: activity_api_enabled: desc_html: Counts of locally published posts, active users, and new registrations in weekly buckets title: Publish aggregate statistics about user activity in the API + allow_poll_image: + desc_html: Allow image attachments to polls, which is prohibited by Mastodon standard + title: Allow to attach image to poll bootstrap_timeline_accounts: desc_html: Separate multiple usernames by comma. These accounts will be guaranteed to be shown in follow recommendations title: Recommend these accounts to new users diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 076800f34..008253d97 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -606,6 +606,9 @@ ja: activity_api_enabled: desc_html: 週ごとのローカルに投稿された投稿数、アクティブなユーザー数、新規登録者数 title: ユーザーアクティビティに関する統計を公開する + allow_poll_image: + desc_html: Mastodon標準で禁止されている投票へのイメージ添付を許可します + title: 投票にイメージ添付を許可 bootstrap_timeline_accounts: desc_html: 複数のユーザー名を指定する場合コンマで区切ります。おすすめに表示されます。 title: 新規ユーザーにおすすめするアカウント diff --git a/config/settings.yml b/config/settings.yml index 9cde602e1..5293a8926 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -138,6 +138,7 @@ defaults: &defaults hide_link_preview: false hide_photo_preview: false hide_video_preview: false + allow_poll_image: false development: <<: *defaults