Setting up preliminary "detailed" routes in the UI, new API end-point for fetching status context
This commit is contained in:
		| @@ -1,11 +1,22 @@ | ||||
| import api from '../api' | ||||
|  | ||||
| export const ACCOUNT_SET_SELF      = 'ACCOUNT_SET_SELF'; | ||||
| export const ACCOUNT_SET_SELF = 'ACCOUNT_SET_SELF'; | ||||
|  | ||||
| export const ACCOUNT_FETCH         = 'ACCOUNT_FETCH'; | ||||
| export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; | ||||
| export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; | ||||
| export const ACCOUNT_FETCH_FAIL    = 'ACCOUNT_FETCH_FAIL'; | ||||
|  | ||||
| export const ACCOUNT_FOLLOW         = 'ACCOUNT_FOLLOW'; | ||||
| export const ACCOUNT_FOLLOW_REQUEST = 'ACCOUNT_FOLLOW_REQUEST'; | ||||
| export const ACCOUNT_FOLLOW_SUCCESS = 'ACCOUNT_FOLLOW_SUCCESS'; | ||||
| export const ACCOUNT_FOLLOW_FAIL    = 'ACCOUNT_FOLLOW_FAIL'; | ||||
|  | ||||
| export const ACCOUNT_UNFOLLOW         = 'ACCOUNT_UNFOLLOW'; | ||||
| export const ACCOUNT_UNFOLLOW_REQUEST = 'ACCOUNT_UNFOLLOW_REQUEST'; | ||||
| export const ACCOUNT_UNFOLLOW_SUCCESS = 'ACCOUNT_UNFOLLOW_SUCCESS'; | ||||
| export const ACCOUNT_UNFOLLOW_FAIL    = 'ACCOUNT_UNFOLLOW_FAIL'; | ||||
|  | ||||
| export function setAccountSelf(account) { | ||||
|   return { | ||||
|     type: ACCOUNT_SET_SELF, | ||||
| @@ -46,3 +57,69 @@ export function fetchAccountFail(id, error) { | ||||
|     error: error | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function followAccount(id) { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch(followAccountRequest(id)); | ||||
|  | ||||
|     api(getState).post(`/api/accounts/${id}/follow`).then(response => { | ||||
|       dispatch(followAccountSuccess(response.data)); | ||||
|     }).catch(error => { | ||||
|       dispatch(followAccountFail(error)); | ||||
|     }); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function unfollowAccount(id) { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch(unfollowAccountRequest(id)); | ||||
|  | ||||
|     api(getState).post(`/api/accounts/${id}/unfollow`).then(response => { | ||||
|       dispatch(unfollowAccountSuccess(response.data)); | ||||
|     }).catch(error => { | ||||
|       dispatch(unfollowAccountFail(error)); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export function followAccountRequest(id) { | ||||
|   return { | ||||
|     type: ACCOUNT_FOLLOW_REQUEST, | ||||
|     id: id | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function followAccountSuccess(account) { | ||||
|   return { | ||||
|     type: ACCOUNT_FOLLOW_SUCCESS, | ||||
|     account: account | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function followAccountFail(error) { | ||||
|   return { | ||||
|     type: ACCOUNT_FOLLOW_FAIL, | ||||
|     error: error | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function unfollowAccountRequest(id) { | ||||
|   return { | ||||
|     type: ACCOUNT_UNFOLLOW_REQUEST, | ||||
|     id: id | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function unfollowAccountSuccess(account) { | ||||
|   return { | ||||
|     type: ACCOUNT_UNFOLLOW_SUCCESS, | ||||
|     account: account | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function unfollowAccountFail(error) { | ||||
|   return { | ||||
|     type: ACCOUNT_UNFOLLOW_FAIL, | ||||
|     error: error | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,44 @@ | ||||
| import api from '../api'; | ||||
| import api   from '../api'; | ||||
| import axios from 'axios'; | ||||
|  | ||||
| export const STATUS_FETCH         = 'STATUS_FETCH'; | ||||
| export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | ||||
| export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | ||||
| export const STATUS_FETCH_FAIL    = 'STATUS_FETCH_FAIL'; | ||||
|  | ||||
| export function fetchStatusRequest(id) { | ||||
|   return { | ||||
|     type: STATUS_FETCH_REQUEST, | ||||
|     id: id | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function fetchStatus(id) { | ||||
|   return (dispatch, getState) => { | ||||
|     const boundApi = api(getState); | ||||
|  | ||||
|     dispatch(fetchStatusRequest(id)); | ||||
|  | ||||
|     axios.all([boundApi.get(`/api/statuses/${id}`), boundApi.get(`/api/statuses/${id}/context`)]).then(values => { | ||||
|       dispatch(fetchStatusSuccess(values[0].data, values[1].data)); | ||||
|     }).catch(error => { | ||||
|       dispatch(fetchStatusFail(id, error)); | ||||
|     }); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function fetchStatusSuccess(status, context) { | ||||
|   return { | ||||
|     type: STATUS_FETCH_SUCCESS, | ||||
|     status: status, | ||||
|     context: context | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function fetchStatusFail(id, error) { | ||||
|   return { | ||||
|     type: STATUS_FETCH_FAIL, | ||||
|     id: id, | ||||
|     error: error | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ const NavigationBar = React.createClass({ | ||||
|   render () { | ||||
|     return ( | ||||
|       <div style={{ padding: '10px', display: 'flex', cursor: 'default' }}> | ||||
|         <Avatar src={this.props.account.get('avatar')} size={40} /> | ||||
|         <Link to={`/accounts/${this.props.account.get('id')}`} style={{ textDecoration: 'none' }}><Avatar src={this.props.account.get('avatar')} size={40} /></Link> | ||||
|  | ||||
|         <div style={{ flex: '1 1 auto', marginLeft: '8px' }}> | ||||
|           <strong style={{ fontWeight: '500', display: 'block' }}>{this.props.account.get('acct')}</strong> | ||||
|   | ||||
| @@ -32,7 +32,16 @@ const Status = React.createClass({ | ||||
|   }, | ||||
|  | ||||
|   handleClick () { | ||||
|     hashHistory.push(`/statuses/${this.props.status.get('id')}`); | ||||
|     const { status } = this.props; | ||||
|     hashHistory.push(`/statuses/${status.getIn(['reblog', 'id'], status.get('id'))}`); | ||||
|   }, | ||||
|  | ||||
|   handleAccountClick (id, e) { | ||||
|     if (e.button === 0) { | ||||
|       e.preventDefault(); | ||||
|       hashHistory.push(`/accounts/${id}`); | ||||
|       e.stopPropagation(); | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   render () { | ||||
| @@ -46,7 +55,7 @@ const Status = React.createClass({ | ||||
|         <div style={{ cursor: 'pointer' }} onClick={this.handleClick}> | ||||
|           <div style={{ marginLeft: '68px', color: '#616b86', padding: '8px 0', paddingBottom: '2px', fontSize: '14px', position: 'relative' }}> | ||||
|             <div style={{ position: 'absolute', 'left': '-26px'}}><i className='fa fa-fw fa-retweet'></i></div> | ||||
|             <a href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{status.getIn(['account', 'display_name'])}</strong></a> reblogged | ||||
|             <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name'><strong style={{ color: '#616b86'}}>{status.getIn(['account', 'display_name'])}</strong></a> reblogged | ||||
|           </div> | ||||
|  | ||||
|           <Status {...other} wrapped={true} status={status.get('reblog')} /> | ||||
| @@ -65,7 +74,7 @@ const Status = React.createClass({ | ||||
|             <a href={status.get('url')} className='status__relative-time' style={{ color: '#616b86' }}><RelativeTimestamp timestamp={status.get('created_at')} /></a> | ||||
|           </div> | ||||
|  | ||||
|           <a href={status.getIn(['account', 'url'])} className='status__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px', color: '#616b86' }}> | ||||
|           <a onClick={this.handleAccountClick.bind(this, status.getIn(['account', 'id']))} href={status.getIn(['account', 'url'])} className='status__display-name' style={{ display: 'block', maxWidth: '100%', paddingRight: '25px', color: '#616b86' }}> | ||||
|             <div style={{ position: 'absolute', left: '10px', top: '10px', width: '48px', height: '48px' }}> | ||||
|               <Avatar src={status.getIn(['account', 'avatar'])} size={48} /> | ||||
|             </div> | ||||
|   | ||||
| @@ -6,6 +6,10 @@ import { setAccessToken }                                                    fro | ||||
| import { setAccountSelf }                                                    from '../actions/accounts'; | ||||
| import PureRenderMixin                                                       from 'react-addons-pure-render-mixin'; | ||||
| import { Router, Route, hashHistory }                                        from 'react-router'; | ||||
| import Account                                                               from '../features/account'; | ||||
| import Settings                                                              from '../features/settings'; | ||||
| import Status                                                                from '../features/status'; | ||||
| import Subscriptions                                                         from '../features/subscriptions'; | ||||
|  | ||||
| const store = configureStore(); | ||||
|  | ||||
| @@ -55,10 +59,10 @@ const Root = React.createClass({ | ||||
|       <Provider store={store}> | ||||
|         <Router history={hashHistory}> | ||||
|           <Route path='/' component={Frontend}> | ||||
|             <Route path='/settings' component={null} /> | ||||
|             <Route path='/subscriptions' component={null} /> | ||||
|             <Route path='/statuses/:statusId' component={null} /> | ||||
|             <Route path='/accounts/:accountId' component={null} /> | ||||
|             <Route path='/settings' component={Settings} /> | ||||
|             <Route path='/subscriptions' component={Subscriptions} /> | ||||
|             <Route path='/statuses/:statusId' component={Status} /> | ||||
|             <Route path='/accounts/:accountId' component={Account} /> | ||||
|           </Route> | ||||
|         </Router> | ||||
|       </Provider> | ||||
|   | ||||
							
								
								
									
										79
									
								
								app/assets/javascripts/components/features/account/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								app/assets/javascripts/components/features/account/index.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| import { connect }                                      from 'react-redux'; | ||||
| import PureRenderMixin                                  from 'react-addons-pure-render-mixin'; | ||||
| import ImmutablePropTypes                               from 'react-immutable-proptypes'; | ||||
| import { fetchAccount, followAccount, unfollowAccount } from '../../actions/accounts'; | ||||
| import Button                                           from '../../components/button'; | ||||
|  | ||||
| function selectAccount(state, id) { | ||||
|   return state.getIn(['timelines', 'accounts', id], null); | ||||
| } | ||||
|  | ||||
| const mapStateToProps = (state, props) => ({ | ||||
|   account: selectAccount(state, Number(props.params.accountId)) | ||||
| }); | ||||
|  | ||||
| const Account = React.createClass({ | ||||
|  | ||||
|   propTypes: { | ||||
|     params: React.PropTypes.object.isRequired, | ||||
|     dispatch: React.PropTypes.func.isRequired, | ||||
|     account: ImmutablePropTypes.map | ||||
|   }, | ||||
|  | ||||
|   mixins: [PureRenderMixin], | ||||
|  | ||||
|   componentWillMount () { | ||||
|     this.props.dispatch(fetchAccount(this.props.params.accountId)); | ||||
|   }, | ||||
|  | ||||
|   componentWillReceiveProps(nextProps) { | ||||
|     if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) { | ||||
|       this.props.dispatch(fetchAccount(nextProps.params.accountId)); | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   handleFollowClick () { | ||||
|     this.props.dispatch(followAccount(this.props.account.get('id'))); | ||||
|   }, | ||||
|  | ||||
|   handleUnfollowClick () { | ||||
|     this.props.dispatch(unfollowAccount(this.props.account.get('id'))); | ||||
|   }, | ||||
|  | ||||
|   render () { | ||||
|     const { account } = this.props; | ||||
|     let action; | ||||
|  | ||||
|     if (account === null) { | ||||
|       return <div>Loading {this.props.params.accountId}...</div>; | ||||
|     } | ||||
|  | ||||
|     if (account.get('following')) { | ||||
|       action = <Button text='Unfollow' onClick={this.handleUnfollowClick} />; | ||||
|     } else { | ||||
|       action = <Button text='Follow' onClick={this.handleFollowClick} /> | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|       <div> | ||||
|         <p> | ||||
|           {account.get('display_name')} | ||||
|           {account.get('acct')} | ||||
|         </p> | ||||
|  | ||||
|         {account.get('url')} | ||||
|  | ||||
|         <p>{account.get('note')}</p> | ||||
|  | ||||
|         {account.get('followers_count')} followers<br /> | ||||
|         {account.get('following_count')} following<br /> | ||||
|         {account.get('statuses_count')} posts | ||||
|  | ||||
|         <p>{action}</p> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| }); | ||||
|  | ||||
| export default connect(mapStateToProps)(Account); | ||||
| @@ -0,0 +1,28 @@ | ||||
| import { connect }        from 'react-redux'; | ||||
| import PureRenderMixin    from 'react-addons-pure-render-mixin'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
|  | ||||
| const mapStateToProps = (state, props) => ({ | ||||
|  | ||||
| }); | ||||
|  | ||||
| const Settings = React.createClass({ | ||||
|  | ||||
|   propTypes: { | ||||
|     params: React.PropTypes.object.isRequired, | ||||
|     dispatch: React.PropTypes.func.isRequired | ||||
|   }, | ||||
|  | ||||
|   mixins: [PureRenderMixin], | ||||
|  | ||||
|   componentWillMount () { | ||||
|     // | ||||
|   }, | ||||
|  | ||||
|   render () { | ||||
|     return <div>Settings</div>; | ||||
|   } | ||||
|  | ||||
| }); | ||||
|  | ||||
| export default connect(mapStateToProps)(Settings); | ||||
							
								
								
									
										74
									
								
								app/assets/javascripts/components/features/status/index.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								app/assets/javascripts/components/features/status/index.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| import { connect }              from 'react-redux'; | ||||
| import PureRenderMixin          from 'react-addons-pure-render-mixin'; | ||||
| import ImmutablePropTypes       from 'react-immutable-proptypes'; | ||||
| import { fetchStatus }          from '../../actions/statuses'; | ||||
| import Immutable                from 'immutable'; | ||||
| import EmbeddedStatus           from '../../components/status'; | ||||
|  | ||||
| function selectStatus(state, id) { | ||||
|   let status = state.getIn(['timelines', 'statuses', id]); | ||||
|  | ||||
|   status = status.set('account', state.getIn(['timelines', 'accounts', status.get('account')])); | ||||
|  | ||||
|   if (status.get('reblog') !== null) { | ||||
|     status = status.set('reblog', selectStatus(state, status.get('reblog'))); | ||||
|   } | ||||
|  | ||||
|   return status; | ||||
| }; | ||||
|  | ||||
| function selectStatuses(state, ids) { | ||||
|   return ids.map(id => selectStatus(state, id)); | ||||
| }; | ||||
|  | ||||
| const mapStateToProps = (state, props) => ({ | ||||
|   status: selectStatus(state, Number(props.params.statusId)), | ||||
|   ancestors: selectStatuses(state, state.getIn(['timelines', 'ancestors', Number(props.params.statusId)], Immutable.List())), | ||||
|   descendants: selectStatuses(state, state.getIn(['timelines', 'descendants', Number(props.params.statusId)], Immutable.List())) | ||||
| }); | ||||
|  | ||||
| const Status = React.createClass({ | ||||
|  | ||||
|   propTypes: { | ||||
|     params: React.PropTypes.object.isRequired, | ||||
|     dispatch: React.PropTypes.func.isRequired, | ||||
|     status: ImmutablePropTypes.map, | ||||
|     ancestors: ImmutablePropTypes.list.isRequired, | ||||
|     descendants: ImmutablePropTypes.list.isRequired | ||||
|   }, | ||||
|  | ||||
|   mixins: [PureRenderMixin], | ||||
|  | ||||
|   componentWillMount () { | ||||
|     this.props.dispatch(fetchStatus(this.props.params.statusId)); | ||||
|   }, | ||||
|  | ||||
|   componentWillReceiveProps (nextProps) { | ||||
|     if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { | ||||
|       this.props.dispatch(fetchStatus(nextProps.params.statusId)); | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   renderChildren (list) { | ||||
|     return list.map(s => <EmbeddedStatus status={s} key={s.get('id')} />); | ||||
|   }, | ||||
|  | ||||
|   render () { | ||||
|     const { status, ancestors, descendants } = this.props; | ||||
|  | ||||
|     if (status === null) { | ||||
|       return <div>Loading {this.props.params.statusId}...</div>; | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|       <div> | ||||
|         {this.renderChildren(ancestors)} | ||||
|         <EmbeddedStatus status={status} /> | ||||
|         {this.renderChildren(descendants)} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| }); | ||||
|  | ||||
| export default connect(mapStateToProps)(Status); | ||||
| @@ -0,0 +1,28 @@ | ||||
| import { connect }        from 'react-redux'; | ||||
| import PureRenderMixin    from 'react-addons-pure-render-mixin'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
|  | ||||
| const mapStateToProps = (state, props) => ({ | ||||
|  | ||||
| }); | ||||
|  | ||||
| const Subscriptions = React.createClass({ | ||||
|  | ||||
|   propTypes: { | ||||
|     params: React.PropTypes.object.isRequired, | ||||
|     dispatch: React.PropTypes.func.isRequired | ||||
|   }, | ||||
|  | ||||
|   mixins: [PureRenderMixin], | ||||
|  | ||||
|   componentWillMount () { | ||||
|     // | ||||
|   }, | ||||
|  | ||||
|   render () { | ||||
|     return <div>Subscriptions</div>; | ||||
|   } | ||||
|  | ||||
| }); | ||||
|  | ||||
| export default connect(mapStateToProps)(Subscriptions); | ||||
| @@ -1,6 +1,7 @@ | ||||
| import { TIMELINE_SET, TIMELINE_UPDATE, TIMELINE_DELETE } from '../actions/timelines'; | ||||
| import { REBLOG_SUCCESS, FAVOURITE_SUCCESS }              from '../actions/interactions'; | ||||
| import { ACCOUNT_SET_SELF }                               from '../actions/accounts'; | ||||
| import { ACCOUNT_SET_SELF, ACCOUNT_FETCH_SUCCESS }        from '../actions/accounts'; | ||||
| import { STATUS_FETCH_SUCCESS }                           from '../actions/statuses'; | ||||
| import Immutable                                          from 'immutable'; | ||||
|  | ||||
| const initialState = Immutable.Map({ | ||||
| @@ -8,7 +9,9 @@ const initialState = Immutable.Map({ | ||||
|   mentions: Immutable.List([]), | ||||
|   statuses: Immutable.Map(), | ||||
|   accounts: Immutable.Map(), | ||||
|   me: null | ||||
|   me: null, | ||||
|   ancestors: Immutable.Map(), | ||||
|   descendants: Immutable.Map() | ||||
| }); | ||||
|  | ||||
| function statusToMaps(state, status) { | ||||
| @@ -54,6 +57,29 @@ function deleteStatus(state, id) { | ||||
|   return state.deleteIn(['statuses', id]); | ||||
| }; | ||||
|  | ||||
| function accountToMaps(state, account) { | ||||
|   return state.setIn(['accounts', account.get('id')], account); | ||||
| }; | ||||
|  | ||||
| function contextToMaps(state, status, ancestors, descendants) { | ||||
|   state = statusToMaps(state, status); | ||||
|  | ||||
|   let ancestorsIds = ancestors.map(ancestor => { | ||||
|     state = statusToMaps(state, ancestor); | ||||
|     return ancestor.get('id'); | ||||
|   }); | ||||
|  | ||||
|   let descendantsIds = descendants.map(descendant => { | ||||
|     state = statusToMaps(state, descendant); | ||||
|     return descendant.get('id'); | ||||
|   }); | ||||
|  | ||||
|   return state.withMutations(map => { | ||||
|     map.setIn(['ancestors', status.get('id')], ancestorsIds); | ||||
|     map.setIn(['descendants', status.get('id')], descendantsIds); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| export default function timelines(state = initialState, action) { | ||||
|   switch(action.type) { | ||||
|     case TIMELINE_SET: | ||||
| @@ -70,6 +96,10 @@ export default function timelines(state = initialState, action) { | ||||
|         map.setIn(['accounts', action.account.id], Immutable.fromJS(action.account)); | ||||
|         map.set('me', action.account.id); | ||||
|       }); | ||||
|     case ACCOUNT_FETCH_SUCCESS: | ||||
|       return accountToMaps(state, Immutable.fromJS(action.account)); | ||||
|     case STATUS_FETCH_SUCCESS: | ||||
|       return contextToMaps(state, Immutable.fromJS(action.status), Immutable.fromJS(action.context.ancestors), Immutable.fromJS(action.context.descendants)); | ||||
|     default: | ||||
|       return state; | ||||
|   } | ||||
|   | ||||
| @@ -6,6 +6,12 @@ class Api::StatusesController < ApiController | ||||
|     @status = Status.find(params[:id]) | ||||
|   end | ||||
|  | ||||
|   def context | ||||
|     @status      = Status.find(params[:id]) | ||||
|     @ancestors   = @status.ancestors.with_includes.with_counters | ||||
|     @descendants = @status.descendants.with_includes.with_counters | ||||
|   end | ||||
|  | ||||
|   def create | ||||
|     @status = PostStatusService.new.(current_user.account, params[:status], params[:in_reply_to_id].blank? ? nil : Status.find(params[:in_reply_to_id]), params[:media_ids]) | ||||
|     render action: :show | ||||
|   | ||||
							
								
								
									
										13
									
								
								app/views/api/statuses/context.rabl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/views/api/statuses/context.rabl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| object false | ||||
|  | ||||
| node :ancestors do | ||||
|   @ancestors.map do |status| | ||||
|     partial('api/statuses/show', object: status) | ||||
|   end | ||||
| end | ||||
|  | ||||
| node :descendants do | ||||
|   @descendants.map do |status| | ||||
|     partial('api/statuses/show', object: status) | ||||
|   end | ||||
| end | ||||
| @@ -47,6 +47,8 @@ Rails.application.routes.draw do | ||||
|       end | ||||
|  | ||||
|       member do | ||||
|         get :context | ||||
|  | ||||
|         post :reblog | ||||
|         post :favourite | ||||
|       end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user