Remove Neo4J
This commit is contained in:
		
							parent
							
								
									fca183968e
								
							
						
					
					
						commit
						8efa081f21
					
				
					 23 changed files with 6 additions and 323 deletions
				
			
		|  | @ -1,37 +0,0 @@ | |||
| import api from '../api'; | ||||
| 
 | ||||
| export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST'; | ||||
| export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS'; | ||||
| export const SUGGESTIONS_FETCH_FAIL    = 'SUGGESTIONS_FETCH_FAIL'; | ||||
| 
 | ||||
| export function fetchSuggestions() { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch(fetchSuggestionsRequest()); | ||||
| 
 | ||||
|     api(getState).get('/api/v1/accounts/suggestions').then(response => { | ||||
|       dispatch(fetchSuggestionsSuccess(response.data)); | ||||
|     }).catch(error => { | ||||
|       dispatch(fetchSuggestionsFail(error)); | ||||
|     }); | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export function fetchSuggestionsRequest() { | ||||
|   return { | ||||
|     type: SUGGESTIONS_FETCH_REQUEST | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export function fetchSuggestionsSuccess(accounts) { | ||||
|   return { | ||||
|     type: SUGGESTIONS_FETCH_SUCCESS, | ||||
|     accounts: accounts | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export function fetchSuggestionsFail(error) { | ||||
|   return { | ||||
|     type: SUGGESTIONS_FETCH_FAIL, | ||||
|     error: error | ||||
|   }; | ||||
| }; | ||||
|  | @ -1,86 +0,0 @@ | |||
| import PureRenderMixin from 'react-addons-pure-render-mixin'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import AccountContainer from '../../../containers/account_container'; | ||||
| import { FormattedMessage } from 'react-intl'; | ||||
| 
 | ||||
| const outerStyle = { | ||||
|   position: 'relative' | ||||
| }; | ||||
| 
 | ||||
| const headerStyle = { | ||||
|   fontSize: '14px', | ||||
|   fontWeight: '500', | ||||
|   display: 'block', | ||||
|   padding: '10px', | ||||
|   color: '#9baec8', | ||||
|   background: '#454b5e', | ||||
|   overflow: 'hidden' | ||||
| }; | ||||
| 
 | ||||
| const nextStyle = { | ||||
|   display: 'inline-block', | ||||
|   float: 'right', | ||||
|   fontWeight: '400', | ||||
|   color: '#2b90d9' | ||||
| }; | ||||
| 
 | ||||
| const SuggestionsBox = React.createClass({ | ||||
| 
 | ||||
|   propTypes: { | ||||
|     accountIds: ImmutablePropTypes.list, | ||||
|     perWindow: React.PropTypes.number | ||||
|   }, | ||||
| 
 | ||||
|   getInitialState () { | ||||
|     return { | ||||
|       index: 0 | ||||
|     }; | ||||
|   }, | ||||
| 
 | ||||
|   getDefaultProps () { | ||||
|     return { | ||||
|       perWindow: 2 | ||||
|     }; | ||||
|   }, | ||||
| 
 | ||||
|   mixins: [PureRenderMixin], | ||||
| 
 | ||||
|   handleNextClick (e) { | ||||
|     e.preventDefault(); | ||||
| 
 | ||||
|     let newIndex = this.state.index + 1; | ||||
| 
 | ||||
|     if (this.props.accountIds.skip(this.props.perWindow * newIndex).size === 0) { | ||||
|       newIndex = 0; | ||||
|     } | ||||
| 
 | ||||
|     this.setState({ index: newIndex }); | ||||
|   }, | ||||
| 
 | ||||
|   render () { | ||||
|     const { accountIds, perWindow } = this.props; | ||||
| 
 | ||||
|     if (!accountIds || accountIds.size === 0) { | ||||
|       return <div />; | ||||
|     } | ||||
| 
 | ||||
|     let nextLink = ''; | ||||
| 
 | ||||
|     if (accountIds.size > perWindow) { | ||||
|       nextLink = <a href='#' style={nextStyle} onClick={this.handleNextClick}><FormattedMessage id='suggestions_box.refresh' defaultMessage='Refresh' /></a>; | ||||
|     } | ||||
| 
 | ||||
|     return ( | ||||
|       <div style={outerStyle}> | ||||
|         <strong style={headerStyle}> | ||||
|           <FormattedMessage id='suggestions_box.who_to_follow' defaultMessage='Who to follow' /> {nextLink} | ||||
|         </strong> | ||||
| 
 | ||||
|         {accountIds.skip(perWindow * this.state.index).take(perWindow).map(accountId => <AccountContainer key={accountId} id={accountId} withNote={false} />)} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| export default SuggestionsBox; | ||||
|  | @ -1,8 +0,0 @@ | |||
| import { connect }           from 'react-redux'; | ||||
| import SuggestionsBox        from '../components/suggestions_box'; | ||||
| 
 | ||||
| const mapStateToProps = (state) => ({ | ||||
|   accountIds: state.getIn(['user_lists', 'suggestions']) | ||||
| }); | ||||
| 
 | ||||
| export default connect(mapStateToProps)(SuggestionsBox); | ||||
|  | @ -3,9 +3,7 @@ import ComposeFormContainer from './containers/compose_form_container'; | |||
| import UploadFormContainer from './containers/upload_form_container'; | ||||
| import NavigationContainer from './containers/navigation_container'; | ||||
| import PureRenderMixin from 'react-addons-pure-render-mixin'; | ||||
| import SuggestionsContainer from './containers/suggestions_container'; | ||||
| import SearchContainer from './containers/search_container'; | ||||
| import { fetchSuggestions } from '../../actions/suggestions'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { mountCompose, unmountCompose } from '../../actions/compose'; | ||||
| 
 | ||||
|  | @ -19,7 +17,6 @@ const Compose = React.createClass({ | |||
| 
 | ||||
|   componentDidMount () { | ||||
|     this.props.dispatch(mountCompose()); | ||||
|     this.props.dispatch(fetchSuggestions()); | ||||
|   }, | ||||
| 
 | ||||
|   componentWillUnmount () { | ||||
|  | @ -29,14 +26,10 @@ const Compose = React.createClass({ | |||
|   render () { | ||||
|     return ( | ||||
|       <Drawer> | ||||
|         <div style={{ flex: '1 1 auto' }}> | ||||
|           <SearchContainer /> | ||||
|           <NavigationContainer /> | ||||
|           <ComposeFormContainer /> | ||||
|           <UploadFormContainer /> | ||||
|         </div> | ||||
| 
 | ||||
|         <SuggestionsContainer /> | ||||
|         <SearchContainer /> | ||||
|         <NavigationContainer /> | ||||
|         <ComposeFormContainer /> | ||||
|         <UploadFormContainer /> | ||||
|       </Drawer> | ||||
|     ); | ||||
|   } | ||||
|  |  | |||
|  | @ -41,8 +41,6 @@ const en = { | |||
|   "search.placeholder": "Suche", | ||||
|   "search.account": "Konto", | ||||
|   "search.hashtag": "Hashtag", | ||||
|   "suggestions_box.who_to_follow": "Wem folgen", | ||||
|   "suggestions_box.refresh": "Aktualisieren", | ||||
|   "upload_button.label": "Media-Datei anfügen", | ||||
|   "upload_form.undo": "Entfernen", | ||||
|   "notification.follow": "{name} folgt dir", | ||||
|  |  | |||
|  | @ -45,8 +45,6 @@ const en = { | |||
|   "search.placeholder": "Search", | ||||
|   "search.account": "Account", | ||||
|   "search.hashtag": "Hashtag", | ||||
|   "suggestions_box.who_to_follow": "Who to follow", | ||||
|   "suggestions_box.refresh": "Refresh", | ||||
|   "upload_button.label": "Add media", | ||||
|   "upload_form.undo": "Undo", | ||||
|   "notification.follow": "{name} followed you", | ||||
|  |  | |||
|  | @ -42,8 +42,6 @@ const es = { | |||
|   "search.placeholder": "Buscar", | ||||
|   "search.account": "Cuenta", | ||||
|   "search.hashtag": "Etiqueta", | ||||
|   "suggestions_box.who_to_follow": "A quién seguir", | ||||
|   "suggestions_box.refresh": "Refrescar", | ||||
|   "upload_button.label": "Añadir medio", | ||||
|   "upload_form.undo": "Deshacer", | ||||
|   "notification.follow": "{name} le esta ahora siguiendo", | ||||
|  |  | |||
|  | @ -41,8 +41,6 @@ const fr = { | |||
|   "search.placeholder": "Chercher", | ||||
|   "search.account": "Compte", | ||||
|   "search.hashtag": "Mot-clé", | ||||
|   "suggestions_box.who_to_follow": "Suggestions", | ||||
|   "suggestions_box.refresh": "Rafraîchir", | ||||
|   "upload_button.label": "Joindre un média", | ||||
|   "upload_form.undo": "Annuler", | ||||
|   "notification.follow": "{name} s’est abonné⋅e à vos statuts", | ||||
|  |  | |||
|  | @ -40,8 +40,6 @@ const pt = { | |||
|   "search.placeholder": "Busca", | ||||
|   "search.account": "Conta", | ||||
|   "search.hashtag": "Hashtag", | ||||
|   "suggestions_box.who_to_follow": "Quem seguir", | ||||
|   "suggestions_box.refresh": "Recarregar", | ||||
|   "upload_button.label": "Adicionar media", | ||||
|   "upload_form.undo": "Desfazer" | ||||
| }; | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ import { | |||
|   FOLLOWING_FETCH_SUCCESS, | ||||
|   FOLLOWING_EXPAND_SUCCESS | ||||
| } from '../actions/accounts'; | ||||
| import { SUGGESTIONS_FETCH_SUCCESS } from '../actions/suggestions'; | ||||
| import { | ||||
|   REBLOGS_FETCH_SUCCESS, | ||||
|   FAVOURITES_FETCH_SUCCESS | ||||
|  | @ -14,7 +13,6 @@ import Immutable from 'immutable'; | |||
| const initialState = Immutable.Map({ | ||||
|   followers: Immutable.Map(), | ||||
|   following: Immutable.Map(), | ||||
|   suggestions: Immutable.List(), | ||||
|   reblogged_by: Immutable.Map(), | ||||
|   favourited_by: Immutable.Map() | ||||
| }); | ||||
|  | @ -42,8 +40,6 @@ export default function userLists(state = initialState, action) { | |||
|       return normalizeList(state, 'following', action.id, action.accounts, action.next); | ||||
|     case FOLLOWING_EXPAND_SUCCESS: | ||||
|       return appendToList(state, 'following', action.id, action.accounts, action.next); | ||||
|     case SUGGESTIONS_FETCH_SUCCESS: | ||||
|       return state.set('suggestions', Immutable.List(action.accounts.map(item => item.id))); | ||||
|     case REBLOGS_FETCH_SUCCESS: | ||||
|       return state.setIn(['reblogged_by', action.id], Immutable.List(action.accounts.map(item => item.id))); | ||||
|     case FAVOURITES_FETCH_SUCCESS: | ||||
|  |  | |||
|  | @ -46,16 +46,6 @@ class Api::V1::AccountsController < ApiController | |||
|     render action: :index | ||||
|   end | ||||
| 
 | ||||
|   def common_followers | ||||
|     @accounts = @account.common_followers_with(current_user.account) | ||||
|     render action: :index | ||||
|   end | ||||
| 
 | ||||
|   def suggestions | ||||
|     @accounts = FollowSuggestion.get(current_user.account_id) | ||||
|     render action: :index | ||||
|   end | ||||
| 
 | ||||
|   def statuses | ||||
|     @statuses = @account.statuses.paginate_by_max_id(DEFAULT_STATUSES_LIMIT, params[:max_id], params[:since_id]).to_a | ||||
|     @statuses = cache(@statuses) | ||||
|  |  | |||
|  | @ -130,15 +130,6 @@ class Account < ApplicationRecord | |||
|     username | ||||
|   end | ||||
| 
 | ||||
|   def common_followers_with(other_account) | ||||
|     results  = Neography::Rest.new.execute_query('MATCH (a {account_id: {a_id}})-[:follows]->(b)-[:follows]->(c {account_id: {c_id}}) RETURN b.account_id', a_id: id, c_id: other_account.id) | ||||
|     ids      = results['data'].map(&:first) | ||||
|     accounts = Account.where(id: ids).with_counters.limit(20).map { |a| [a.id, a] }.to_h | ||||
|     ids.map { |id| accounts[id] }.compact | ||||
|   rescue Neography::NeographyError, Excon::Error::Socket | ||||
|     [] | ||||
|   end | ||||
| 
 | ||||
|   class << self | ||||
|     def find_local!(username) | ||||
|       find_remote!(username, nil) | ||||
|  |  | |||
|  | @ -27,32 +27,4 @@ class Follow < ApplicationRecord | |||
|   def title | ||||
|     destroyed? ? "#{account.acct} is no longer following #{target_account.acct}" : "#{account.acct} started following #{target_account.acct}" | ||||
|   end | ||||
| 
 | ||||
|   after_create  :add_to_graph | ||||
|   after_destroy :remove_from_graph | ||||
| 
 | ||||
|   def sync! | ||||
|     add_to_graph | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def add_to_graph | ||||
|     neo = Neography::Rest.new | ||||
| 
 | ||||
|     a = neo.create_unique_node('account_index', 'Account', account_id.to_s, account_id: account_id) | ||||
|     b = neo.create_unique_node('account_index', 'Account', target_account_id.to_s, account_id: target_account_id) | ||||
| 
 | ||||
|     neo.create_unique_relationship('follow_index', 'Follow', id.to_s, 'follows', a, b) | ||||
|   rescue Neography::NeographyError, Excon::Error::Socket => e | ||||
|     Rails.logger.error e | ||||
|   end | ||||
| 
 | ||||
|   def remove_from_graph | ||||
|     neo = Neography::Rest.new | ||||
|     rel = neo.get_relationship_index('follow_index', 'Follow', id.to_s) | ||||
|     neo.delete_relationship(rel) | ||||
|   rescue Neography::NeographyError, Excon::Error::Socket => e | ||||
|     Rails.logger.error e | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -1,50 +0,0 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| class FollowSuggestion | ||||
|   class << self | ||||
|     def get(for_account_id, limit = 10) | ||||
|       neo = Neography::Rest.new | ||||
| 
 | ||||
|       query = <<END | ||||
| MATCH (a {account_id: {id}})-[:follows]->(b)-[:follows]->(c) | ||||
| WHERE a <> c | ||||
| AND NOT (a)-[:follows]->(c) | ||||
| RETURN DISTINCT c.account_id, count(b), c.nodeRank | ||||
| ORDER BY count(b) DESC, c.nodeRank DESC | ||||
| LIMIT {limit} | ||||
| END | ||||
| 
 | ||||
|       results = neo.execute_query(query, id: for_account_id, limit: limit) | ||||
| 
 | ||||
|       if results.empty? || results['data'].empty? | ||||
|         results = fallback(for_account_id, limit) | ||||
|       elsif results['data'].size < limit | ||||
|         results['data'] = (results['data'] + fallback(for_account_id, limit - results['data'].size)['data']).uniq | ||||
|       end | ||||
| 
 | ||||
|       account_ids  = results['data'].map(&:first) | ||||
|       blocked_ids  = Block.where(account_id: for_account_id).pluck(:target_account_id) | ||||
|       accounts_map = Account.where(id: account_ids - blocked_ids).with_counters.map { |a| [a.id, a] }.to_h | ||||
| 
 | ||||
|       account_ids.map { |id| accounts_map[id] }.compact | ||||
|     rescue Neography::NeographyError, Excon::Error::Socket => e | ||||
|       Rails.logger.error e | ||||
|       return [] | ||||
|     end | ||||
| 
 | ||||
|     private | ||||
| 
 | ||||
|     def fallback(for_account_id, limit) | ||||
|       neo = Neography::Rest.new | ||||
| 
 | ||||
|       query = <<END | ||||
| MATCH (b) | ||||
| RETURN b.account_id | ||||
| ORDER BY b.nodeRank DESC | ||||
| LIMIT {limit} | ||||
| END | ||||
| 
 | ||||
|       neo.execute_query(query, id: for_account_id, limit: limit) | ||||
|     end | ||||
|   end | ||||
| end | ||||
		Reference in a new issue