Fix notifications in UI, added new API for fetching account relationships
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| export const NOTIFICATION_DISMISS = 'NOTIFICATION_DISMISS'; | ||||
| export const NOTIFICATION_CLEAR   = 'NOTIFICATION_CLEAR'; | ||||
|  | ||||
| export function dismissNotification(notification) { | ||||
|   return { | ||||
| @@ -6,3 +7,9 @@ export function dismissNotification(notification) { | ||||
|     notification: notification | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function clearNotifications() { | ||||
|   return { | ||||
|     type: NOTIFICATION_CLEAR | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| import { connect }             from 'react-redux'; | ||||
| import { NotificationStack }   from 'react-notification'; | ||||
| import { dismissNotification } from '../../../actions/notifications'; | ||||
| import { | ||||
|   dismissNotification, | ||||
|   clearNotifications | ||||
| }                              from '../../../actions/notifications'; | ||||
|  | ||||
| const mapStateToProps = (state, props) => { | ||||
|   return { | ||||
|     notifications: state.get('notifications').map((item, i) => ({ | ||||
|       message: item.get('message'), | ||||
|       title: item.get('title'), | ||||
|       key: i, | ||||
|       action: 'Dismiss', | ||||
|       dismissAfter: 5000 | ||||
|     })).toJS() | ||||
|   }; | ||||
| }; | ||||
| const mapStateToProps = (state, props) => ({ | ||||
|   notifications: state.get('notifications').map((item, i) => ({ | ||||
|     message: item.get('message'), | ||||
|     title: item.get('title'), | ||||
|     key: item.get('key'), | ||||
|     dismissAfter: 5000 | ||||
|   })).toJS() | ||||
| }); | ||||
|  | ||||
| const mapDispatchToProps = (dispatch) => { | ||||
|   return { | ||||
|   | ||||
| @@ -2,13 +2,14 @@ import { COMPOSE_SUBMIT_FAIL, COMPOSE_UPLOAD_FAIL } from '../actions/compose'; | ||||
| import { FOLLOW_SUBMIT_FAIL }                       from '../actions/follow'; | ||||
| import { REBLOG_FAIL, FAVOURITE_FAIL }              from '../actions/interactions'; | ||||
| 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'; | ||||
|  | ||||
| const initialState = Immutable.List(); | ||||
|  | ||||
| function notificationFromError(state, error) { | ||||
|   let n = Immutable.Map({ | ||||
|     key: state.size > 0 ? state.last().get('key') + 1 : 0, | ||||
|     message: '' | ||||
|   }); | ||||
|  | ||||
| @@ -34,6 +35,8 @@ export default function notifications(state = initialState, action) { | ||||
|     case TIMELINE_REFRESH_FAIL: | ||||
|       return notificationFromError(state, action.error); | ||||
|     case NOTIFICATION_DISMISS: | ||||
|       return state.filterNot(item => item.get('key') === action.notification.key); | ||||
|     case NOTIFICATION_CLEAR: | ||||
|       return state.clear(); | ||||
|     default: | ||||
|       return state; | ||||
|   | ||||
| @@ -28,6 +28,14 @@ class Api::AccountsController < ApiController | ||||
|     render action: :show | ||||
|   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 | ||||
|  | ||||
|   def set_account | ||||
|   | ||||
| @@ -127,6 +127,14 @@ class Account < ApplicationRecord | ||||
|     nil | ||||
|   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 | ||||
|     if local? | ||||
|       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(:following_count) { |account| account.following.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 :accounts, only: [:show] do | ||||
|       collection do | ||||
|         get :relationships | ||||
|       end | ||||
|  | ||||
|       member do | ||||
|         get :statuses | ||||
|         get :followers | ||||
|   | ||||
| @@ -71,4 +71,46 @@ RSpec.describe Api::AccountsController, type: :controller do | ||||
|       expect(user.account.following?(other_account)).to be false | ||||
|     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 | ||||
|   | ||||
| @@ -23,5 +23,5 @@ def body_as_json | ||||
| end | ||||
|  | ||||
| def json_str_to_hash(str) | ||||
|   JSON.parse(str).with_indifferent_access | ||||
|   JSON.parse(str, symbolize_names: true) | ||||
| end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user