diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index bfcf1934adb29e..3621e8ca265cbc 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -78,17 +78,7 @@ def set_thread
end
def set_circle
- @circle = begin
- if status_params[:circle_id].blank?
- nil
- elsif status_params[:circle_id] == 'thread' && @thread.present?
- Account.where(id: (@thread.ancestors(CONTEXT_LIMIT, current_account).pluck(:account_id) + [@thread.account_id]).uniq - [current_user.account_id])
- elsif status_params[:circle_id] == 'reply' && @thread.present?
- Account.where(id: [@thread.account_id] - [current_user.account_id])
- else
- current_account.owned_circles.find(status_params[:circle_id])
- end
- end
+ @circle = status_params[:circle_id].blank? ? nil : current_account.owned_circles.find(status_params[:circle_id])
rescue ActiveRecord::RecordNotFound
render json: { error: I18n.t('statuses.errors.circle_not_found') }, status: 404
end
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index f27e4497e61bff..4f5d71683e0039 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -147,7 +147,7 @@ export function submitCompose(routerHistory) {
sensitive: getState().getIn(['compose', 'sensitive']),
spoiler_text: getState().getIn(['compose', 'spoiler']) ? getState().getIn(['compose', 'spoiler_text'], '') : '',
visibility: getState().getIn(['compose', 'privacy']),
- circle_id: getState().getIn(['compose', 'privacy']) === 'limited' ? getState().getIn(['compose', 'circle_id']) : null,
+ circle_id: getState().getIn(['compose', 'circle_id']),
poll: getState().getIn(['compose', 'poll'], null),
}, {
headers: {
diff --git a/app/javascript/mastodon/actions/statuses.js b/app/javascript/mastodon/actions/statuses.js
index e565e0b0ab59d5..45d82dadfeaf04 100644
--- a/app/javascript/mastodon/actions/statuses.js
+++ b/app/javascript/mastodon/actions/statuses.js
@@ -133,10 +133,11 @@ export function fetchStatusFail(id, error, skipLoading) {
};
};
-export function redraft(status, raw_text) {
+export function redraft(status, replyStatus, raw_text) {
return {
type: REDRAFT,
status,
+ replyStatus,
raw_text,
};
};
@@ -144,6 +145,7 @@ export function redraft(status, raw_text) {
export function deleteStatus(id, routerHistory, withRedraft = false) {
return (dispatch, getState) => {
let status = getState().getIn(['statuses', id]);
+ const replyStatus = status.get('in_reply_to_id') ? getState().getIn(['statuses', status.get('in_reply_to_id')]) : null;
if (status.get('poll')) {
status = status.set('poll', getState().getIn(['polls', status.get('poll')]));
@@ -158,7 +160,7 @@ export function deleteStatus(id, routerHistory, withRedraft = false) {
dispatch(importFetchedAccount(response.data.account));
if (withRedraft) {
- dispatch(redraft(status, response.data.text));
+ dispatch(redraft(status, replyStatus, response.data.text));
ensureComposeIsVisible(getState, routerHistory);
}
}).catch(error => {
diff --git a/app/javascript/mastodon/features/compose/components/circle_dropdown.js b/app/javascript/mastodon/features/compose/components/circle_dropdown.js
index 59a0720fa5f42e..3b1bfdf5943a1f 100644
--- a/app/javascript/mastodon/features/compose/components/circle_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/circle_dropdown.js
@@ -8,11 +8,7 @@ import IconButton from 'mastodon/components/icon_button';
import { createSelector } from 'reselect';
const messages = defineMessages({
- circle_system: { id: 'circle.system_definition', defaultMessage: 'System definition' },
- circle_user: { id: 'circle.user_definition', defaultMessage: 'User definition' },
circle_unselect: { id: 'circle.unselect', defaultMessage: '(Select circle)' },
- circle_reply_to_poster: { id: 'circle.reply-to_poster', defaultMessage: 'Reply-to poster' },
- circle_thread_posters: { id: 'circle.thread_posters', defaultMessage: 'Thread posters' },
circle_open_circle_column: { id: 'circle.open_circle_column', defaultMessage: 'Open circle column' },
circle_select: { id: 'circle.select', defaultMessage: 'Select circle' },
});
@@ -43,7 +39,6 @@ class CircleDropdown extends React.PureComponent {
circles: ImmutablePropTypes.list,
value: PropTypes.string.isRequired,
visible: PropTypes.bool.isRequired,
- reply: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
onOpenCircleColumn: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
@@ -58,7 +53,7 @@ class CircleDropdown extends React.PureComponent {
};
render () {
- const { circles, value, visible, reply, intl } = this.props;
+ const { circles, value, visible, intl } = this.props;
return (
@@ -67,16 +62,9 @@ class CircleDropdown extends React.PureComponent {
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
);
diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
index 8b7130567a06bb..5d6957e8b07111 100644
--- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
@@ -31,6 +31,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
style: PropTypes.object,
items: PropTypes.array.isRequired,
value: PropTypes.string.isRequired,
+ enableValues: PropTypes.array.isRequired,
placement: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
@@ -121,7 +122,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
render () {
const { mounted } = this.state;
- const { style, items, placement, value } = this.props;
+ const { style, items, placement, value, enableValues } = this.props;
return (
@@ -131,6 +132,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
// react-overlays
{items.map(item => (
+ enableValues.includes(item.value) &&
@@ -159,6 +161,7 @@ class PrivacyDropdown extends React.PureComponent {
onModalOpen: PropTypes.func,
onModalClose: PropTypes.func,
value: PropTypes.string.isRequired,
+ limitedReply: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
};
@@ -244,10 +247,11 @@ class PrivacyDropdown extends React.PureComponent {
}
render () {
- const { value, intl } = this.props;
+ const { value, limitedReply, intl } = this.props;
const { open, placement } = this.state;
const valueOption = this.options.find(item => item.value === value);
+ const enableValues = limitedReply ? ['limited', 'direct'] : ['public', 'unlisted', 'private', 'limited', 'direct'];
return (
@@ -271,6 +275,7 @@ class PrivacyDropdown extends React.PureComponent {
{
return {
value: value,
- visible: state.getIn(['compose', 'privacy']) === 'limited',
- reply: state.getIn(['compose', 'in_reply_to']) !== null,
+ visible: state.getIn(['compose', 'privacy']) === 'limited' && state.getIn(['compose', 'reply_status', 'visibility']) !== 'limited',
};
};
diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
index 0df22e8ca000bc..c195245ee0ee27 100644
--- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js
+++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
@@ -23,7 +23,7 @@ const mapStateToProps = state => ({
isSubmitting: state.getIn(['compose', 'is_submitting']),
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
isUploading: state.getIn(['compose', 'is_uploading']),
- isCircleUnselected: state.getIn(['compose', 'privacy']) === 'limited' && !state.getIn(['compose', 'circle_id']),
+ isCircleUnselected: state.getIn(['compose', 'privacy']) === 'limited' && state.getIn(['compose', 'reply_status', 'visibility']) !== 'limited' && !state.getIn(['compose', 'circle_id']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
});
diff --git a/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js
index 0ddf531d3173f1..5afb6d89c7306d 100644
--- a/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js
+++ b/app/javascript/mastodon/features/compose/containers/privacy_dropdown_container.js
@@ -7,6 +7,7 @@ import { isUserTouching } from '../../../is_mobile';
const mapStateToProps = state => ({
isModalOpen: state.get('modal').modalType === 'ACTIONS',
value: state.getIn(['compose', 'privacy']),
+ limitedReply: state.getIn(['compose', 'reply_status', 'visibility']) === 'limited',
});
const mapDispatchToProps = dispatch => ({
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 799ed997256935..99b5a4c8448e25 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -58,12 +58,8 @@
"bundle_modal_error.message": "Something went wrong while loading this component.",
"bundle_modal_error.retry": "Try again",
"circle.open_circle_column": "Open circle column",
- "circle.reply-to_poster": "Reply-to poster",
- "circle.thread_posters": "Thread posters",
"circle.select": "Select circle",
- "circle.system_definition": "System definition",
"circle.unselect": "(Select circle)",
- "circle.user_definition": "User definition",
"column.blocks": "Blocked users",
"column.bookmarks": "Bookmarks",
"column.community": "Local timeline",
diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js
index fd07cd903492b9..acba91990fea54 100644
--- a/app/javascript/mastodon/reducers/compose.js
+++ b/app/javascript/mastodon/reducers/compose.js
@@ -303,11 +303,7 @@ export default function compose(state = initialState, action) {
map.set('text', statusToTextMentions(state.get('text'), action.value, state.get('reply_status')));
map.set('privacy', action.value);
map.set('idempotencyKey', uuid());
- if(action.value === 'limited' && map.get('in_reply_to')) {
- map.set('circle_id', state.getIn(['reply_status', 'in_reply_to_id']) ? 'thread' : 'reply');
- } else {
- map.set('circle_id', null);
- }
+ map.set('circle_id', null);
});
case COMPOSE_CIRCLE_CHANGE:
return state
@@ -327,13 +323,7 @@ export default function compose(state = initialState, action) {
map.set('reply_status', action.status);
map.set('text', statusToTextMentions('', privacy, action.status));
map.set('privacy', privacy);
- if(action.status.get('circle_id')) {
- map.set('circle_id', action.status.get('circle_id'));
- } else if(action.status.get('visibility') === 'limited'){
- map.set('circle_id', action.status.get('in_reply_to_id') ? 'thread' : 'reply');
- } else {
- map.set('circle_id', null);
- }
+ map.set('circle_id', null);
map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('preselectDate', new Date());
@@ -444,7 +434,7 @@ export default function compose(state = initialState, action) {
return state.withMutations(map => {
map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status)));
map.set('in_reply_to', action.status.get('in_reply_to_id'));
- map.set('reply_status', action.status);
+ map.set('reply_status', action.replyStatus);
map.set('privacy', action.status.get('visibility'));
map.set('circle_id', action.status.get('circle_id'));
map.set('media_attachments', action.status.get('media_attachments'));
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index 51aa4fcbcc7721..66c577e515dd28 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -68,7 +68,7 @@ def limited
end
def limited_owned_status?
- object.limited_visibility? && owned_status?
+ object.limited_visibility? && owned_status? && object.in_reply_to_id.nil?
end
def circle_id
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 467cc4d7b87c21..be880c4a3d3cac 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -68,7 +68,7 @@ def process_status!
process_hashtags_service.call(@status)
process_mentions_service.call(@status)
- redis.setex(circle_id_key, 3.days.seconds, @circle.id) if @circle.present? && @circle.respond_to?(:id)
+ redis.setex(circle_id_key, 3.days.seconds, @circle.id) if @circle.present?
end
def schedule_status!
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 3590ed4cd76829..e3719eea6438b9 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -43,11 +43,8 @@ def call(status)
end
if circle.present?
- accounts = circle.respond_to?(:accounts) ? circle.accounts : circle
-
- accounts.find_each do |target_account|
- mention = target_account.mentions.new(status: status, silent: true)
- mentions << mention if mention.save!
+ circle.accounts.find_each do |target_account|
+ status.mentions.create(silent: true, account: target_account)
end
end