diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/components/actions/blocks.jsx | 82 | ||||
-rw-r--r-- | app/assets/javascripts/components/containers/mastodon.jsx | 3 | ||||
-rw-r--r-- | app/assets/javascripts/components/features/blocks/index.jsx | 68 | ||||
-rw-r--r-- | app/assets/javascripts/components/reducers/accounts.jsx | 8 | ||||
-rw-r--r-- | app/assets/javascripts/components/reducers/user_lists.jsx | 14 | ||||
-rw-r--r-- | app/models/device.rb | 7 | ||||
-rw-r--r-- | app/services/notify_service.rb | 5 | ||||
-rw-r--r-- | app/services/send_push_notification_service.rb | 28 |
8 files changed, 174 insertions, 41 deletions
diff --git a/app/assets/javascripts/components/actions/blocks.jsx b/app/assets/javascripts/components/actions/blocks.jsx new file mode 100644 index 000000000..79e316497 --- /dev/null +++ b/app/assets/javascripts/components/actions/blocks.jsx @@ -0,0 +1,82 @@ +import api, { getLinks } from '../api' +import { fetchRelationships } from './accounts'; + +export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST'; +export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS'; +export const BLOCKS_FETCH_FAIL = 'BLOCKS_FETCH_FAIL'; + +export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST'; +export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS'; +export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL'; + +export function fetchBlocks() { + return (dispatch, getState) => { + dispatch(fetchBlocksRequest()); + + api(getState).get('/api/v1/blocks').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(fetchBlocksFail(error))); + }; +}; + +export function fetchBlocksRequest() { + return { + type: BLOCKS_FETCH_REQUEST + }; +}; + +export function fetchBlocksSuccess(accounts, next) { + return { + type: BLOCKS_FETCH_SUCCESS, + accounts, + next + }; +}; + +export function fetchBlocksFail(error) { + return { + type: BLOCKS_FETCH_FAIL, + error + }; +}; + +export function expandBlocks() { + return (dispatch, getState) => { + const url = getState().getIn(['user_lists', 'blocks', 'next']); + + if (url === null) { + return; + } + + dispatch(expandBlocksRequest()); + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next'); + dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); + dispatch(fetchRelationships(response.data.map(item => item.id))); + }).catch(error => dispatch(expandBlocksFail(error))); + }; +}; + +export function expandBlocksRequest() { + return { + type: BLOCKS_EXPAND_REQUEST + }; +}; + +export function expandBlocksSuccess(accounts, next) { + return { + type: BLOCKS_EXPAND_SUCCESS, + accounts, + next + }; +}; + +export function expandBlocksFail(error) { + return { + type: BLOCKS_EXPAND_FAIL, + error + }; +}; diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index 46a01b200..3b36ce3ef 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -33,6 +33,7 @@ import Notifications from '../features/notifications'; import FollowRequests from '../features/follow_requests'; import GenericNotFound from '../features/generic_not_found'; import FavouritedStatuses from '../features/favourited_statuses'; +import Blocks from '../features/blocks'; import { IntlProvider, addLocaleData } from 'react-intl'; import en from 'react-intl/locale-data/en'; import de from 'react-intl/locale-data/de'; @@ -124,6 +125,8 @@ const Mastodon = React.createClass({ <Route path='accounts/:accountId/following' component={Following} /> <Route path='follow_requests' component={FollowRequests} /> + <Route path='blocks' component={Blocks} /> + <Route path='*' component={GenericNotFound} /> </Route> </Router> diff --git a/app/assets/javascripts/components/features/blocks/index.jsx b/app/assets/javascripts/components/features/blocks/index.jsx new file mode 100644 index 000000000..9bc226d61 --- /dev/null +++ b/app/assets/javascripts/components/features/blocks/index.jsx @@ -0,0 +1,68 @@ +import { connect } from 'react-redux'; +import PureRenderMixin from 'react-addons-pure-render-mixin'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import LoadingIndicator from '../../components/loading_indicator'; +import { ScrollContainer } from 'react-router-scroll'; +import Column from '../ui/components/column'; +import ColumnBackButtonSlim from '../../components/column_back_button_slim'; +import AccountContainer from '../../containers/account_container'; +import { fetchBlocks, expandBlocks } from '../../actions/blocks'; +import { defineMessages, injectIntl } from 'react-intl'; + +const messages = defineMessages({ + heading: { id: 'column.blocks', defaultMessage: 'Blocked' } +}); + +const mapStateToProps = state => ({ + accountIds: state.getIn(['user_lists', 'blocks', 'items']) +}); + +const Blocks = React.createClass({ + propTypes: { + params: React.PropTypes.object.isRequired, + dispatch: React.PropTypes.func.isRequired, + accountIds: ImmutablePropTypes.list, + intl: React.PropTypes.object.isRequired + }, + + mixins: [PureRenderMixin], + + componentWillMount () { + this.props.dispatch(fetchBlocks()); + }, + + handleScroll (e) { + const { scrollTop, scrollHeight, clientHeight } = e.target; + + if (scrollTop === scrollHeight - clientHeight) { + this.props.dispatch(expandBlocks()); + } + }, + + render () { + const { intl, accountIds } = this.props; + + if (!accountIds) { + return ( + <Column> + <LoadingIndicator /> + </Column> + ); + } + + return ( + <Column icon='users' heading={intl.formatMessage(messages.heading)}> + <ColumnBackButtonSlim /> + <ScrollContainer scrollKey='blocks'> + <div className='scrollable' onScroll={this.handleScroll}> + {accountIds.map(id => + <AccountContainer key={id} id={id} /> + )} + </div> + </ScrollContainer> + </Column> + ); + } +}); + +export default connect(mapStateToProps)(injectIntl(Blocks)); diff --git a/app/assets/javascripts/components/reducers/accounts.jsx b/app/assets/javascripts/components/reducers/accounts.jsx index 409dfd663..f3938cee1 100644 --- a/app/assets/javascripts/components/reducers/accounts.jsx +++ b/app/assets/javascripts/components/reducers/accounts.jsx @@ -7,9 +7,14 @@ import { ACCOUNT_TIMELINE_FETCH_SUCCESS, ACCOUNT_TIMELINE_EXPAND_SUCCESS, FOLLOW_REQUESTS_FETCH_SUCCESS, + FOLLOW_REQUESTS_EXPAND_SUCCESS, ACCOUNT_FOLLOW_SUCCESS, ACCOUNT_UNFOLLOW_SUCCESS } from '../actions/accounts'; +import { + BLOCKS_FETCH_SUCCESS, + BLOCKS_EXPAND_SUCCESS +} from '../actions/blocks'; import { COMPOSE_SUGGESTIONS_READY } from '../actions/compose'; import { REBLOG_SUCCESS, @@ -87,6 +92,9 @@ export default function accounts(state = initialState, action) { case COMPOSE_SUGGESTIONS_READY: case SEARCH_SUGGESTIONS_READY: case FOLLOW_REQUESTS_FETCH_SUCCESS: + case FOLLOW_REQUESTS_EXPAND_SUCCESS: + case BLOCKS_FETCH_SUCCESS: + case BLOCKS_EXPAND_SUCCESS: return normalizeAccounts(state, action.accounts); case NOTIFICATIONS_REFRESH_SUCCESS: case NOTIFICATIONS_EXPAND_SUCCESS: diff --git a/app/assets/javascripts/components/reducers/user_lists.jsx b/app/assets/javascripts/components/reducers/user_lists.jsx index 72922f509..8c9a3d3aa 100644 --- a/app/assets/javascripts/components/reducers/user_lists.jsx +++ b/app/assets/javascripts/components/reducers/user_lists.jsx @@ -4,6 +4,7 @@ import { FOLLOWING_FETCH_SUCCESS, FOLLOWING_EXPAND_SUCCESS, FOLLOW_REQUESTS_FETCH_SUCCESS, + FOLLOW_REQUESTS_EXPAND_SUCCESS, FOLLOW_REQUEST_AUTHORIZE_SUCCESS, FOLLOW_REQUEST_REJECT_SUCCESS } from '../actions/accounts'; @@ -11,6 +12,10 @@ import { REBLOGS_FETCH_SUCCESS, FAVOURITES_FETCH_SUCCESS } from '../actions/interactions'; +import { + BLOCKS_FETCH_SUCCESS, + BLOCKS_EXPAND_SUCCESS +} from '../actions/blocks'; import Immutable from 'immutable'; const initialState = Immutable.Map({ @@ -18,7 +23,8 @@ const initialState = Immutable.Map({ following: Immutable.Map(), reblogged_by: Immutable.Map(), favourited_by: Immutable.Map(), - follow_requests: Immutable.Map() + follow_requests: Immutable.Map(), + blocks: Immutable.Map() }); const normalizeList = (state, type, id, accounts, next) => { @@ -50,9 +56,15 @@ export default function userLists(state = initialState, action) { return state.setIn(['favourited_by', action.id], Immutable.List(action.accounts.map(item => item.id))); case FOLLOW_REQUESTS_FETCH_SUCCESS: return state.setIn(['follow_requests', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next); + case FOLLOW_REQUESTS_EXPAND_SUCCESS: + return state.updateIn(['follow_requests', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next); case FOLLOW_REQUEST_AUTHORIZE_SUCCESS: case FOLLOW_REQUEST_REJECT_SUCCESS: return state.updateIn(['follow_requests', 'items'], list => list.filterNot(item => item === action.id)); + case BLOCKS_FETCH_SUCCESS: + return state.setIn(['blocks', 'items'], Immutable.List(action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next); + case BLOCKS_EXPAND_SUCCESS: + return state.updateIn(['blocks', 'items'], list => list.push(...action.accounts.map(item => item.id))).setIn(['blocks', 'next'], action.next); default: return state; } diff --git a/app/models/device.rb b/app/models/device.rb deleted file mode 100644 index 2782a7f38..000000000 --- a/app/models/device.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -class Device < ApplicationRecord - belongs_to :account - - validates :account, :registration_id, presence: true -end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 0cc3cd618..942cd9d21 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -10,7 +10,6 @@ class NotifyService < BaseService create_notification send_email if email_enabled? - send_push_notification rescue ActiveRecord::RecordInvalid return end @@ -58,10 +57,6 @@ class NotifyService < BaseService NotificationMailer.send(@notification.type, @recipient, @notification).deliver_later end - def send_push_notification - PushNotificationWorker.perform_async(@notification.id) - end - def email_enabled? @recipient.user.settings.notification_emails[@notification.type] end diff --git a/app/services/send_push_notification_service.rb b/app/services/send_push_notification_service.rb deleted file mode 100644 index 526ae20cb..000000000 --- a/app/services/send_push_notification_service.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class SendPushNotificationService < BaseService - def call(notification) - return if ENV['FCM_API_KEY'].blank? - - devices = Device.where(account: notification.account).pluck(:registration_id) - fcm = FCM.new(ENV['FCM_API_KEY']) - - response = fcm.send(devices, data: { notification_id: notification.id }, collapse_key: :notifications, priority: :high) - handle_response(response) - end - - private - - def handle_response(response) - update_canonical_ids(response[:canonical_ids]) if response[:canonical_ids] - remove_bad_ids(response[:not_registered_ids]) if response[:not_registered_ids] - end - - def update_canonical_ids(ids) - ids.each { |pair| Device.find_by(registration_id: pair[:old]).update(registration_id: pair[:new]) } - end - - def remove_bad_ids(bad_ids) - Device.where(registration_id: bad_ids).delete_all unless bad_ids.empty? - end -end |