Chore: Fix presence for current user (#1001)

Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
This commit is contained in:
Sojan Jose 2020-07-04 20:03:16 +05:30 committed by GitHub
parent 4612494923
commit 43147b3163
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 78 additions and 20 deletions

View file

@ -4,17 +4,22 @@ class RoomChannel < ApplicationCable::Channel
current_user current_user
current_account current_account
update_subscription update_subscription
broadcast_presence
end end
def update_presence def update_presence
update_subscription update_subscription
broadcast_presence
end
private
def broadcast_presence
data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) } data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) }
data[:contacts] = ::OnlineStatusTracker.get_available_contacts(@current_account.id) if @current_user.is_a? User data[:contacts] = ::OnlineStatusTracker.get_available_contacts(@current_account.id) if @current_user.is_a? User
ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data }) ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data })
end end
private
def ensure_stream def ensure_stream
@pubsub_token = params[:pubsub_token] @pubsub_token = params[:pubsub_token]
stream_from @pubsub_token stream_from @pubsub_token

View file

@ -33,6 +33,7 @@ class ActionCableConnector extends BaseActionCableConnector {
onPresenceUpdate = data => { onPresenceUpdate = data => {
this.app.$store.dispatch('contacts/updatePresence', data.contacts); this.app.$store.dispatch('contacts/updatePresence', data.contacts);
this.app.$store.dispatch('agents/updatePresence', data.users); this.app.$store.dispatch('agents/updatePresence', data.users);
this.app.$store.dispatch('setCurrentUserAvailabilityStatus', data.users);
}; };
onConversationContactChange = payload => { onConversationContactChange = payload => {

View file

@ -163,6 +163,7 @@ export default {
...mapGetters({ ...mapGetters({
currentUser: 'getCurrentUser', currentUser: 'getCurrentUser',
currentUserId: 'getCurrentUserID', currentUserId: 'getCurrentUserID',
currentAvailabilityStatus: 'getCurrentUserAvailabilityStatus',
}), }),
}, },
watch: { watch: {
@ -171,6 +172,11 @@ export default {
this.initializeUser(); this.initializeUser();
} }
}, },
currentAvailabilityStatus(newStatus, oldStatus) {
if (newStatus !== oldStatus) {
this.availability = newStatus;
}
},
}, },
mounted() { mounted() {
if (this.currentUserId) { if (this.currentUserId) {

View file

@ -5,7 +5,6 @@ import accounts from './modules/accounts';
import agents from './modules/agents'; import agents from './modules/agents';
import auth from './modules/auth'; import auth from './modules/auth';
import cannedResponse from './modules/cannedResponse'; import cannedResponse from './modules/cannedResponse';
import Channel from './modules/channels';
import contactConversations from './modules/contactConversations'; import contactConversations from './modules/contactConversations';
import contacts from './modules/contacts'; import contacts from './modules/contacts';
import conversationLabels from './modules/conversationLabels'; import conversationLabels from './modules/conversationLabels';
@ -30,7 +29,6 @@ export default new Vuex.Store({
agents, agents,
auth, auth,
cannedResponse, cannedResponse,
Channel,
contactConversations, contactConversations,
contacts, contacts,
conversationLabels, conversationLabels,

View file

@ -34,6 +34,10 @@ export const getters = {
return _state.currentUser.id; return _state.currentUser.id;
}, },
getCurrentUserAvailabilityStatus(_state) {
return _state.currentUser.availability_status;
},
getCurrentAccountId(_state) { getCurrentAccountId(_state) {
return _state.currentAccountId; return _state.currentAccountId;
}, },
@ -104,10 +108,22 @@ export const actions = {
setCurrentAccountId({ commit }, accountId) { setCurrentAccountId({ commit }, accountId) {
commit(types.default.SET_CURRENT_ACCOUNT_ID, accountId); commit(types.default.SET_CURRENT_ACCOUNT_ID, accountId);
}, },
setCurrentUserAvailabilityStatus({ commit, state: $state }, data) {
if (data[$state.currentUser.id]) {
commit(
types.default.SET_CURRENT_USER_AVAILABILITY,
data[$state.currentUser.id]
);
}
},
}; };
// mutations // mutations
const mutations = { const mutations = {
[types.default.SET_CURRENT_USER_AVAILABILITY](_state, status) {
Vue.set(_state.currentUser, 'availability_status', status);
},
[types.default.CLEAR_USER](_state) { [types.default.CLEAR_USER](_state) {
_state.currentUser.id = null; _state.currentUser.id = null;
}, },

View file

@ -1,14 +0,0 @@
/* eslint no-console: 0 */
/* eslint no-param-reassign: 0 */
// const chatType = 'all';
// initial state
const state = {};
// actions
const actions = {};
export default {
state,
actions,
};

View file

@ -67,4 +67,30 @@ describe('#actions', () => {
expect(dispatch).toHaveBeenCalledTimes(0); expect(dispatch).toHaveBeenCalledTimes(0);
}); });
}); });
describe('#setCurrentUserAvailabilityStatus', () => {
it('sends correct mutations if user id is available', async () => {
actions.setCurrentUserAvailabilityStatus(
{
commit,
state: { currentUser: { id: 1 } },
},
{ 1: 'online' }
);
expect(commit.mock.calls).toEqual([
[types.default.SET_CURRENT_USER_AVAILABILITY, 'online'],
]);
});
it('does not send correct mutations if user id is not available', async () => {
actions.setCurrentUserAvailabilityStatus(
{
commit,
state: { currentUser: { id: 1 } },
},
{}
);
expect(commit.mock.calls).toEqual([]);
});
});
}); });

View file

@ -17,4 +17,12 @@ describe('#getters', () => {
getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } }) getters.getCurrentUser({ currentUser: { id: 1, name: 'Pranav' } })
).toEqual({ id: 1, name: 'Pranav' }); ).toEqual({ id: 1, name: 'Pranav' });
}); });
it('get', () => {
expect(
getters.getCurrentUserAvailabilityStatus({
currentUser: { id: 1, name: 'Pranav', availability_status: 'busy' },
})
).toEqual('busy');
});
}); });

View file

@ -3,7 +3,7 @@ export default {
CLEAR_USER: 'LOGOUT', CLEAR_USER: 'LOGOUT',
SET_CURRENT_USER: 'SET_CURRENT_USER', SET_CURRENT_USER: 'SET_CURRENT_USER',
SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID', SET_CURRENT_ACCOUNT_ID: 'SET_CURRENT_ACCOUNT_ID',
SET_CURRENT_USER_AVAILABILITY: 'SET_CURRENT_USER_AVAILABILITY',
// Chat List // Chat List
RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST', RECEIVE_CHAT_LIST: 'RECEIVE_CHAT_LIST',
SET_ALL_CONVERSATION: 'SET_ALL_CONVERSATION', SET_ALL_CONVERSATION: 'SET_ALL_CONVERSATION',

View file

@ -2,19 +2,29 @@ module AvailabilityStatusable
extend ActiveSupport::Concern extend ActiveSupport::Concern
def online_presence? def online_presence?
return if user_profile_page_context?
::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id) ::OnlineStatusTracker.get_presence(availability_account_id, self.class.name, id)
end end
def availability_status def availability_status
return availability if user_profile_page_context?
return 'offline' unless online_presence? return 'offline' unless online_presence?
return 'online' if is_a? Contact return 'online' if is_a? Contact
::OnlineStatusTracker.get_status(availability_account_id, id) || 'online' ::OnlineStatusTracker.get_status(availability_account_id, id) || 'online'
end end
def user_profile_page_context?
# at the moment profile pages aren't account scoped
# hence we will return availability attribute instead of true presence
# we will revisit this later
is_a?(User) && Current.account.blank?
end
def availability_account_id def availability_account_id
return account_id if is_a? Contact return account_id if is_a? Contact
Current.account.present? ? Current.account.id : accounts.first.id Current.account.id
end end
end end

View file

@ -44,6 +44,8 @@ module OnlineStatusTracker
def self.get_available_users(account_id) def self.get_available_users(account_id)
user_ids = ::Redis::Alfred.zrangebyscore(presence_key(account_id, 'User'), (Time.zone.now - PRESENCE_DURATION).to_i, Time.now.to_i) user_ids = ::Redis::Alfred.zrangebyscore(presence_key(account_id, 'User'), (Time.zone.now - PRESENCE_DURATION).to_i, Time.now.to_i)
return {} if user_ids.blank?
user_availabilities = ::Redis::Alfred.hmget(status_key(account_id), user_ids) user_availabilities = ::Redis::Alfred.hmget(status_key(account_id), user_ids)
user_ids.map.with_index { |id, index| [id, (user_availabilities[index] || 'online')] }.to_h user_ids.map.with_index { |id, index| [id, (user_availabilities[index] || 'online')] }.to_h
end end