about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2019-06-28 19:11:06 +0200
committerGitHub <noreply@github.com>2019-06-28 19:11:06 +0200
commitf7c0e326ab11a597b17a22dd8889f0690d7ffd73 (patch)
treeac3ecf0c5bb88485d343752b52f521fd71de8fa6
parent6ad870a410c7379eb8f3e719f3ad217354691546 (diff)
parent43698e08cad195df6f85aea26c710c2e1614a4a3 (diff)
Merge pull request #1145 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
-rw-r--r--app/javascript/flavours/glitch/actions/search.js7
-rw-r--r--app/javascript/flavours/glitch/features/compose/components/search_results.js16
-rw-r--r--app/javascript/flavours/glitch/features/compose/containers/search_results_container.js1
-rw-r--r--app/javascript/flavours/glitch/reducers/search.js3
-rw-r--r--app/javascript/flavours/glitch/styles/components/search.scss5
-rw-r--r--app/javascript/mastodon/actions/search.js5
-rw-r--r--app/javascript/mastodon/features/compose/components/search_results.js14
-rw-r--r--app/javascript/mastodon/features/compose/containers/search_results_container.js1
-rw-r--r--app/javascript/mastodon/reducers/search.js3
-rw-r--r--app/javascript/styles/mastodon/components.scss5
-rw-r--r--app/serializers/activitypub/update_poll_serializer.rb2
-rw-r--r--spec/serializers/activitypub/update_poll_spec.rb27
-rw-r--r--spec/workers/activitypub/distribute_poll_update_worker_spec.rb22
13 files changed, 99 insertions, 12 deletions
diff --git a/app/javascript/flavours/glitch/actions/search.js b/app/javascript/flavours/glitch/actions/search.js
index b2d24e10b..9ce77b24b 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 69df8cdc9..dd99f3430 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 {
           </div>
         </div>
       );
+    } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
+      statuses = (
+        <section>
+          <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
+
+          <div className='search-results__info'>
+            <FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching toots by their content is not enabled on this Mastodon server.' />
+          </div>
+        </section>
+      );
     }
 
     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 f9637861a..e4d5f3420 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 9a525bf47..1c32a5b9f 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 7c5039efc..117da362f 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 7c06670eb..0974fdd15 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 e0966f52c..2f338dd24 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 => <StatusContainer key={statusId} id={statusId} />)}
         </div>
       );
+    } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
+      statuses = (
+        <div className='search-results__section'>
+          <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5>
+
+          <div className='search-results__info'>
+            <FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching toots by their content is not enabled on this Mastodon server.' />
+          </div>
+        </div>
+      );
     }
 
     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 f9637861a..623c52881 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 4758defb1..77b7f588c 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 dc750dbfe..1063d1836 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 b894f309f..1d47b9764 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 000000000..f9e035eab
--- /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 000000000..7eb6119fd
--- /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