diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js
index b2d24e10b4c..9ce77b24b91 100644
--- a/app/javascript/flavours/glitch/actions/search.js
+++ b/app/javascript/flavours/glitch/actions/search.js
@@ -48,7 +48,7 @@ export function submitSearch() {
dispatch(importFetchedStatuses(response.data.statuses));
}
- dispatch(fetchSearchSuccess(response.data));
+ dispatch(fetchSearchSuccess(response.data, value));
dispatch(fetchRelationships(response.data.accounts.map(item => item.id)));
}).catch(error => {
dispatch(fetchSearchFail(error));
@@ -62,12 +62,11 @@ export function fetchSearchRequest() {
};
};
-export function fetchSearchSuccess(results) {
+export function fetchSearchSuccess(results, searchTerm) {
return {
type: SEARCH_FETCH_SUCCESS,
results,
- accounts: results.accounts,
- statuses: results.statuses,
+ searchTerm,
};
};
diff --git a/app/javascript/flavours/glitch/features/compose/components/search_results.js b/app/javascript/flavours/glitch/features/compose/components/search_results.js
index 69df8cdc9db..dd99f343040 100644
--- a/app/javascript/flavours/glitch/features/compose/components/search_results.js
+++ b/app/javascript/flavours/glitch/features/compose/components/search_results.js
@@ -7,6 +7,7 @@ import StatusContainer from 'flavours/glitch/containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Hashtag from 'flavours/glitch/components/hashtag';
import Icon from 'flavours/glitch/components/icon';
+import { searchEnabled } from 'flavours/glitch/util/initial_state';
const messages = defineMessages({
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
@@ -20,6 +21,7 @@ class SearchResults extends ImmutablePureComponent {
suggestions: ImmutablePropTypes.list.isRequired,
fetchSuggestions: PropTypes.func.isRequired,
dismissSuggestion: PropTypes.func.isRequired,
+ searchTerm: PropTypes.string,
intl: PropTypes.object.isRequired,
};
@@ -27,8 +29,8 @@ class SearchResults extends ImmutablePureComponent {
this.props.fetchSuggestions();
}
- render() {
- const { intl, results, suggestions, dismissSuggestion } = this.props;
+ render () {
+ const { intl, results, suggestions, dismissSuggestion, searchTerm } = this.props;
if (results.isEmpty() && !suggestions.isEmpty()) {
return (
@@ -51,6 +53,16 @@ class SearchResults extends ImmutablePureComponent {
);
+ } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
+ statuses = (
+
+ );
}
let accounts, statuses, hashtags;
diff --git a/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js b/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js
index f9637861ae7..e4d5f342078 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/search_results_container.js
@@ -5,6 +5,7 @@ import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestion
const mapStateToProps = state => ({
results: state.getIn(['search', 'results']),
suggestions: state.getIn(['suggestions', 'items']),
+ searchTerm: state.getIn(['search', 'searchTerm']),
});
const mapDispatchToProps = dispatch => ({
diff --git a/app/javascript/flavours/glitch/reducers/search.js b/app/javascript/flavours/glitch/reducers/search.js
index 9a525bf47ba..1c32a5b9f73 100644
--- a/app/javascript/flavours/glitch/reducers/search.js
+++ b/app/javascript/flavours/glitch/reducers/search.js
@@ -16,6 +16,7 @@ const initialState = ImmutableMap({
submitted: false,
hidden: false,
results: ImmutableMap(),
+ searchTerm: '',
});
export default function search(state = initialState, action) {
@@ -40,7 +41,7 @@ export default function search(state = initialState, action) {
accounts: ImmutableList(action.results.accounts.map(item => item.id)),
statuses: ImmutableList(action.results.statuses.map(item => item.id)),
hashtags: fromJS(action.results.hashtags),
- })).set('submitted', true);
+ })).set('submitted', true).set('searchTerm', action.searchTerm);
default:
return state;
}
diff --git a/app/javascript/flavours/glitch/styles/components/search.scss b/app/javascript/flavours/glitch/styles/components/search.scss
index 7c5039efcac..117da362fc0 100644
--- a/app/javascript/flavours/glitch/styles/components/search.scss
+++ b/app/javascript/flavours/glitch/styles/components/search.scss
@@ -78,6 +78,11 @@
font-weight: 500;
}
+.search-results__info {
+ padding: 10px;
+ color: $secondary-text-color;
+}
+
.trends {
&__header {
color: $dark-text-color;
diff --git a/app/javascript/mastodon/actions/search.js b/app/javascript/mastodon/actions/search.js
index 7c06670eb53..0974fdd15e6 100644
--- a/app/javascript/mastodon/actions/search.js
+++ b/app/javascript/mastodon/actions/search.js
@@ -48,7 +48,7 @@ export function submitSearch() {
dispatch(importFetchedStatuses(response.data.statuses));
}
- dispatch(fetchSearchSuccess(response.data));
+ dispatch(fetchSearchSuccess(response.data, value));
dispatch(fetchRelationships(response.data.accounts.map(item => item.id)));
}).catch(error => {
dispatch(fetchSearchFail(error));
@@ -62,10 +62,11 @@ export function fetchSearchRequest() {
};
};
-export function fetchSearchSuccess(results) {
+export function fetchSearchSuccess(results, searchTerm) {
return {
type: SEARCH_FETCH_SUCCESS,
results,
+ searchTerm,
};
};
diff --git a/app/javascript/mastodon/features/compose/components/search_results.js b/app/javascript/mastodon/features/compose/components/search_results.js
index e0966f52c43..2f338dd2469 100644
--- a/app/javascript/mastodon/features/compose/components/search_results.js
+++ b/app/javascript/mastodon/features/compose/components/search_results.js
@@ -7,6 +7,7 @@ import StatusContainer from '../../../containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Hashtag from '../../../components/hashtag';
import Icon from 'mastodon/components/icon';
+import { searchEnabled } from '../../../initial_state';
const messages = defineMessages({
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
@@ -20,6 +21,7 @@ class SearchResults extends ImmutablePureComponent {
suggestions: ImmutablePropTypes.list.isRequired,
fetchSuggestions: PropTypes.func.isRequired,
dismissSuggestion: PropTypes.func.isRequired,
+ searchTerm: PropTypes.string,
intl: PropTypes.object.isRequired,
};
@@ -28,7 +30,7 @@ class SearchResults extends ImmutablePureComponent {
}
render () {
- const { intl, results, suggestions, dismissSuggestion } = this.props;
+ const { intl, results, suggestions, dismissSuggestion, searchTerm } = this.props;
if (results.isEmpty() && !suggestions.isEmpty()) {
return (
@@ -76,6 +78,16 @@ class SearchResults extends ImmutablePureComponent {
{results.get('statuses').map(statusId => )}
);
+ } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
+ statuses = (
+
+ );
}
if (results.get('hashtags') && results.get('hashtags').size > 0) {
diff --git a/app/javascript/mastodon/features/compose/containers/search_results_container.js b/app/javascript/mastodon/features/compose/containers/search_results_container.js
index f9637861ae7..623c528813f 100644
--- a/app/javascript/mastodon/features/compose/containers/search_results_container.js
+++ b/app/javascript/mastodon/features/compose/containers/search_results_container.js
@@ -5,6 +5,7 @@ import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestion
const mapStateToProps = state => ({
results: state.getIn(['search', 'results']),
suggestions: state.getIn(['suggestions', 'items']),
+ searchTerm: state.getIn(['search', 'value']),
});
const mapDispatchToProps = dispatch => ({
diff --git a/app/javascript/mastodon/reducers/search.js b/app/javascript/mastodon/reducers/search.js
index 4758defb1b9..77b7f588c58 100644
--- a/app/javascript/mastodon/reducers/search.js
+++ b/app/javascript/mastodon/reducers/search.js
@@ -16,6 +16,7 @@ const initialState = ImmutableMap({
submitted: false,
hidden: false,
results: ImmutableMap(),
+ searchTerm: '',
});
export default function search(state = initialState, action) {
@@ -40,7 +41,7 @@ export default function search(state = initialState, action) {
accounts: ImmutableList(action.results.accounts.map(item => item.id)),
statuses: ImmutableList(action.results.statuses.map(item => item.id)),
hashtags: fromJS(action.results.hashtags),
- })).set('submitted', true);
+ })).set('submitted', true).set('searchTerm', action.searchTerm);
default:
return state;
}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index dc750dbfe16..1063d183663 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -3996,6 +3996,11 @@ a.status-card.compact:hover {
}
}
+.search-results__info {
+ padding: 10px;
+ color: $secondary-text-color;
+}
+
.modal-root {
position: relative;
transition: opacity 0.3s linear;
diff --git a/app/serializers/activitypub/update_poll_serializer.rb b/app/serializers/activitypub/update_poll_serializer.rb
index b894f309ff4..1d47b976435 100644
--- a/app/serializers/activitypub/update_poll_serializer.rb
+++ b/app/serializers/activitypub/update_poll_serializer.rb
@@ -14,7 +14,7 @@ class ActivityPub::UpdatePollSerializer < ActivityPub::Serializer
end
def actor
- ActivityPub::TagManager.instance.uri_for(object)
+ ActivityPub::TagManager.instance.uri_for(object.account)
end
def to
diff --git a/spec/serializers/activitypub/update_poll_spec.rb b/spec/serializers/activitypub/update_poll_spec.rb
new file mode 100644
index 00000000000..f9e035eab58
--- /dev/null
+++ b/spec/serializers/activitypub/update_poll_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe ActivityPub::UpdatePollSerializer do
+ let(:account) { Fabricate(:account) }
+ let(:poll) { Fabricate(:poll, account: account) }
+ let!(:status) { Fabricate(:status, account: account, poll: poll) }
+
+ before(:each) do
+ @serialization = ActiveModelSerializers::SerializableResource.new(status, serializer: ActivityPub::UpdatePollSerializer, adapter: ActivityPub::Adapter)
+ end
+
+ subject { JSON.parse(@serialization.to_json) }
+
+ it 'has a Update type' do
+ expect(subject['type']).to eql('Update')
+ end
+
+ it 'has an object with Question type' do
+ expect(subject['object']['type']).to eql('Question')
+ end
+
+ it 'has the correct actor URI set' do
+ expect(subject['actor']).to eql(ActivityPub::TagManager.instance.uri_for(account))
+ end
+end
diff --git a/spec/workers/activitypub/distribute_poll_update_worker_spec.rb b/spec/workers/activitypub/distribute_poll_update_worker_spec.rb
new file mode 100644
index 00000000000..7eb6119fd80
--- /dev/null
+++ b/spec/workers/activitypub/distribute_poll_update_worker_spec.rb
@@ -0,0 +1,22 @@
+require 'rails_helper'
+
+describe ActivityPub::DistributePollUpdateWorker do
+ subject { described_class.new }
+
+ let(:account) { Fabricate(:account) }
+ let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com') }
+ let(:poll) { Fabricate(:poll, account: account) }
+ let!(:status) { Fabricate(:status, account: account, poll: poll) }
+
+ describe '#perform' do
+ before do
+ allow(ActivityPub::DeliveryWorker).to receive(:push_bulk)
+ follower.follow!(account)
+ end
+
+ it 'delivers to followers' do
+ subject.perform(status.id)
+ expect(ActivityPub::DeliveryWorker).to have_received(:push_bulk).with(['http://example.com'])
+ end
+ end
+end