Fix notifications in UI, added new API for fetching account relationships
This commit is contained in:
		
							parent
							
								
									4bec613897
								
							
						
					
					
						commit
						e46abc71ca
					
				| @ -1,4 +1,5 @@ | |||||||
| export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS'; | export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS'; | ||||||
|  | export const NOTIFICATION_CLEAR   = 'NOTIFICATION_CLEAR'; | ||||||
| 
 | 
 | ||||||
| export function dismissNotification(notification) { | export function dismissNotification(notification) { | ||||||
|   return { |   return { | ||||||
| @ -6,3 +7,9 @@ export function dismissNotification(notification) { | |||||||
|     notification: notification |     notification: notification | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export function clearNotifications() { | ||||||
|  |   return { | ||||||
|  |     type: NOTIFICATION_CLEAR | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -1,18 +1,18 @@ | |||||||
| import { connect }             from 'react-redux'; | import { connect }             from 'react-redux'; | ||||||
| import { NotificationStack }   from 'react-notification'; | import { NotificationStack }   from 'react-notification'; | ||||||
| import { dismissNotification } from '../../../actions/notifications'; | import { | ||||||
|  |   dismissNotification, | ||||||
|  |   clearNotifications | ||||||
|  | }                              from '../../../actions/notifications'; | ||||||
| 
 | 
 | ||||||
| const mapStateToProps = (state, props) => { | const mapStateToProps = (state, props) => ({ | ||||||
|   return { |   notifications: state.get('notifications').map((item, i) => ({ | ||||||
|     notifications: state.get('notifications').map((item, i) => ({ |     message: item.get('message'), | ||||||
|       message: item.get('message'), |     title: item.get('title'), | ||||||
|       title: item.get('title'), |     key: item.get('key'), | ||||||
|       key: i, |     dismissAfter: 5000 | ||||||
|       action: 'Dismiss', |   })).toJS() | ||||||
|       dismissAfter: 5000 | }); | ||||||
|     })).toJS() |  | ||||||
|   }; |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| const mapDispatchToProps = (dispatch) => { | const mapDispatchToProps = (dispatch) => { | ||||||
|   return { |   return { | ||||||
|  | |||||||
| @ -2,13 +2,14 @@ import { COMPOSE_SUBMIT_FAIL, COMPOSE_UPLOAD_FAIL } from '../actions/compose'; | |||||||
| import { FOLLOW_SUBMIT_FAIL }                       from '../actions/follow'; | import { FOLLOW_SUBMIT_FAIL }                       from '../actions/follow'; | ||||||
| import { REBLOG_FAIL, FAVOURITE_FAIL }              from '../actions/interactions'; | import { REBLOG_FAIL, FAVOURITE_FAIL }              from '../actions/interactions'; | ||||||
| import { TIMELINE_REFRESH_FAIL }                    from '../actions/timelines'; | import { TIMELINE_REFRESH_FAIL }                    from '../actions/timelines'; | ||||||
| import { NOTIFICATION_DISMISS }                     from '../actions/notifications'; | import { NOTIFICATION_DISMISS, NOTIFICATION_CLEAR } from '../actions/notifications'; | ||||||
| import Immutable                                    from 'immutable'; | import Immutable                                    from 'immutable'; | ||||||
| 
 | 
 | ||||||
| const initialState = Immutable.List(); | const initialState = Immutable.List(); | ||||||
| 
 | 
 | ||||||
| function notificationFromError(state, error) { | function notificationFromError(state, error) { | ||||||
|   let n = Immutable.Map({ |   let n = Immutable.Map({ | ||||||
|  |     key: state.size > 0 ? state.last().get('key') + 1 : 0, | ||||||
|     message: '' |     message: '' | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| @ -34,6 +35,8 @@ export default function notifications(state = initialState, action) { | |||||||
|     case TIMELINE_REFRESH_FAIL: |     case TIMELINE_REFRESH_FAIL: | ||||||
|       return notificationFromError(state, action.error); |       return notificationFromError(state, action.error); | ||||||
|     case NOTIFICATION_DISMISS: |     case NOTIFICATION_DISMISS: | ||||||
|  |       return state.filterNot(item => item.get('key') === action.notification.key); | ||||||
|  |     case NOTIFICATION_CLEAR: | ||||||
|       return state.clear(); |       return state.clear(); | ||||||
|     default: |     default: | ||||||
|       return state; |       return state; | ||||||
|  | |||||||
| @ -28,6 +28,14 @@ class Api::AccountsController < ApiController | |||||||
|     render action: :show |     render action: :show | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def relationships | ||||||
|  |     ids = params[:id].is_a?(Enumerable) ? params[:id].map { |id| id.to_i } : [params[:id].to_i] | ||||||
|  |     @accounts    = Account.find(ids) | ||||||
|  |     @following   = Account.following_map(ids, current_user.account_id) | ||||||
|  |     @followed_by = Account.followed_by_map(ids, current_user.account_id) | ||||||
|  |     @blocking    = {} | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   private |   private | ||||||
| 
 | 
 | ||||||
|   def set_account |   def set_account | ||||||
|  | |||||||
| @ -127,6 +127,14 @@ class Account < ApplicationRecord | |||||||
|     nil |     nil | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   def self.following_map(target_account_ids, account_id) | ||||||
|  |     Follow.where(target_account_id: target_account_ids).where(account_id: account_id).map { |f| [f.target_account_id, true] }.to_h | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   def self.followed_by_map(target_account_ids, account_id) | ||||||
|  |     Follow.where(account_id: target_account_ids).where(target_account_id: account_id).map { |f| [f.account_id, true] }.to_h | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   before_create do |   before_create do | ||||||
|     if local? |     if local? | ||||||
|       keypair = OpenSSL::PKey::RSA.new(Rails.env.test? ? 1024 : 2048) |       keypair = OpenSSL::PKey::RSA.new(Rails.env.test? ? 1024 : 2048) | ||||||
|  | |||||||
| @ -1,2 +0,0 @@ | |||||||
| collection @accounts |  | ||||||
| extends('api/accounts/show') |  | ||||||
							
								
								
									
										5
									
								
								app/views/api/accounts/relationships.rabl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/views/api/accounts/relationships.rabl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | collection @accounts | ||||||
|  | attribute :id | ||||||
|  | node(:following)   { |account| @following[account.id]   || false } | ||||||
|  | node(:followed_by) { |account| @followed_by[account.id] || false } | ||||||
|  | node(:blocking)    { |account| @blocking[account.id]    || false } | ||||||
| @ -8,4 +8,3 @@ node(:header)          { |account| full_asset_url(account.header.url(:medium, fa | |||||||
| node(:followers_count) { |account| account.followers.count } | node(:followers_count) { |account| account.followers.count } | ||||||
| node(:following_count) { |account| account.following.count } | node(:following_count) { |account| account.following.count } | ||||||
| node(:statuses_count)  { |account| account.statuses.count  } | node(:statuses_count)  { |account| account.statuses.count  } | ||||||
| node(:following)       { |account| current_account.following?(account) } |  | ||||||
|  | |||||||
| @ -59,6 +59,10 @@ Rails.application.routes.draw do | |||||||
|     resources :media,    only: [:create] |     resources :media,    only: [:create] | ||||||
| 
 | 
 | ||||||
|     resources :accounts, only: [:show] do |     resources :accounts, only: [:show] do | ||||||
|  |       collection do | ||||||
|  |         get :relationships | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|       member do |       member do | ||||||
|         get :statuses |         get :statuses | ||||||
|         get :followers |         get :followers | ||||||
|  | |||||||
| @ -71,4 +71,46 @@ RSpec.describe Api::AccountsController, type: :controller do | |||||||
|       expect(user.account.following?(other_account)).to be false |       expect(user.account.following?(other_account)).to be false | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   describe 'GET #relationships' do | ||||||
|  |     let(:simon) { Fabricate(:user, email: 'simon@example.com', account: Fabricate(:account, username: 'simon')).account } | ||||||
|  |     let(:lewis) { Fabricate(:user, email: 'lewis@example.com', account: Fabricate(:account, username: 'lewis')).account } | ||||||
|  | 
 | ||||||
|  |     before do | ||||||
|  |       user.account.follow!(simon) | ||||||
|  |       lewis.follow!(user.account) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'provided only one ID' do | ||||||
|  |       before do | ||||||
|  |         get :relationships, params: { id: simon.id } | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns http success' do | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns JSON with correct data' do | ||||||
|  |         json = body_as_json | ||||||
|  | 
 | ||||||
|  |         expect(json).to be_a Enumerable | ||||||
|  |         expect(json.first[:following]).to be true | ||||||
|  |         expect(json.first[:followed_by]).to be false | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'provided multiple IDs' do | ||||||
|  |       before do | ||||||
|  |         get :relationships, params: { id: [simon.id, lewis.id] } | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       it 'returns http success' do | ||||||
|  |         expect(response).to have_http_status(:success) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       xit 'returns JSON with correct data' do | ||||||
|  |         # todo | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  | |||||||
| @ -23,5 +23,5 @@ def body_as_json | |||||||
| end | end | ||||||
| 
 | 
 | ||||||
| def json_str_to_hash(str) | def json_str_to_hash(str) | ||||||
|   JSON.parse(str).with_indifferent_access |   JSON.parse(str, symbolize_names: true) | ||||||
| end | end | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user