Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Send LiveChat visitor navigation history as messages #10091

Merged
merged 21 commits into from
Jun 5, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2fb6d12
Fix livechat routes to allow inviting other agents to the same chat.
renatobecker Feb 26, 2018
41e7cbd
Fix indentation tabs.
renatobecker Feb 26, 2018
089e15e
Merge branch 'fix-invite-agents-to-livechat-rooms' into send-visitor-…
renatobecker Feb 27, 2018
587ffda
Started working on send visitor navigation history as a message to ag…
renatobecker Feb 28, 2018
460b76b
- Sending the navigation history of the visitor as a message;
renatobecker Mar 9, 2018
221c595
Fix Ci build validations.
renatobecker Mar 12, 2018
bc8c03d
Fix PR review.
renatobecker Mar 12, 2018
5b4ec2a
Fix filter of the navigation history subscribe.
renatobecker Mar 14, 2018
57d0bf3
Fix PR review.
renatobecker Mar 14, 2018
d86fb7b
Merge branch 'develop' into send-visitor-navigaton-history-as-a-message
renatobecker May 18, 2018
cacc518
Merge branch 'develop' into send-visitor-navigaton-history-as-a-message
renatobecker May 29, 2018
a25f9ea
New feature added to send messages related to Livechat visitor naviga…
renatobecker May 29, 2018
632baf1
Fix codacy-bot review issues.
renatobecker May 29, 2018
f4c62d8
Merge branch 'develop' into send-visitor-navigaton-history-as-a-message
sampaiodiego Jun 4, 2018
d314565
Fix coding styling
sampaiodiego Jun 5, 2018
2cc736b
Do not return message on pageVisited method
sampaiodiego Jun 5, 2018
bf90817
Better styling for navigation history messages
sampaiodiego Jun 5, 2018
b2535ea
Improved livechat history migration to run faster
sampaiodiego Jun 5, 2018
cb2274d
Disable showing livechat navigation history as message by default
sampaiodiego Jun 5, 2018
c086d6c
Better visitor navigation translation
sampaiodiego Jun 5, 2018
b350a0b
Remove unnecessary files
sampaiodiego Jun 5, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
"LivechatDepartmentAgents" : false,
"livechatManagerRoutes" : true,
"LivechatPageVisited" : false,
"LivechatMessage" : false,
"LivechatTrigger" : false,
"Logger" : false,
"Match" : false,
Expand Down
4 changes: 4 additions & 0 deletions packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@
"False": "False",
"Favorite_Rooms": "Enable Favorite Rooms",
"Favorites": "Favorites",
"Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled": "This feature depends on \"Send Visitor Navigation History as a Message\" to be enabled.",
"Features_Enabled": "Features Enabled",
"Field": "Field",
"Field_removed": "Field removed",
Expand Down Expand Up @@ -1463,6 +1464,8 @@
"Mobile_Notifications_Default_Alert": "Mobile Notifications Default Alert",
"Monday": "Monday",
"Monitor_history_for_changes_on": "Monitor History for Changes on",
"Send_Visitor_navigation_history_as_a_message": "Send Visitor Navigation History as a Message",
"Send_visitor_navigation_history_on_request": "Send Visitor Navigation History on Request",
"More_channels": "More channels",
"More_direct_messages": "More direct messages",
"More_groups": "More private groups",
Expand Down Expand Up @@ -1505,6 +1508,7 @@
"New_Trigger": "New Trigger",
"New_version_available_(s)": "New version available (%s)",
"New_videocall_request": "New Video Call Request",
"New_visitor_navigation": "New Visitor Navigation",
"No_available_agents_to_transfer": "No available agents to transfer",
"No_channel_with_name_%s_was_found": "No channel with name <strong>\"%s\"</strong> was found!",
"No_channels_yet": "You aren't part of any channel yet",
Expand Down
4 changes: 4 additions & 0 deletions packages/rocketchat-i18n/i18n/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@
"False": "Não",
"Favorite_Rooms": "Ativar salas favoritas",
"Favorites": "Favoritos",
"Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled": "Esta Funcionalidade depende que \"Enviar histórico de navegação do visitante como mensagem\" esteja habilitada.",
"Features_Enabled": "Funcionalidades habilitadas",
"Field": "Campo",
"Field_removed": "Campo removido",
Expand Down Expand Up @@ -1458,6 +1459,7 @@
"New_Trigger": "Novo Gatilho",
"New_version_available_(s)": "Nova versão disponível (% s)",
"New_videocall_request": "Nova requisição de chamada de vídeo",
"New_visitor_navigation": "Nova Navegação do visitante",
"No_available_agents_to_transfer": "Nenhum agente disponível para transferir",
"No_channel_with_name_%s_was_found": "Nenhum canal com nome <strong>\"%s\"</strong> foi encontrado!",
"No_channels_yet": "Você não faz parte de nenhum canal ainda.",
Expand Down Expand Up @@ -1818,6 +1820,8 @@
"Send_request_on_visitor_message": "Enviar requisição para mensagens do Visitante",
"Send_request_on_agent_message": "Enviar requisição para mensagens do Agente",
"Send_Test": "Enviar teste",
"Send_Visitor_navigation_history_as_a_message": "Enviar histórico de navegação do visitante como mensagem",
"Send_visitor_navigation_history_on_request": "Enviar histórico de navegação do visitante na requisição",
"Send_welcome_email": "Enviar e-mail de boas-vindas",
"Send_your_JSON_payloads_to_this_URL": "Envie seu payload JSON para esta URL.",
"Sending": "Enviando ...",
Expand Down
39 changes: 39 additions & 0 deletions packages/rocketchat-lib/server/models/Messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base {
return this.findOne(query);
}

findByRoomIdAndType(roomId, type, options) {
const query = {
rid: roomId,
t: type
};

if (options == null) { options = {}; }

return this.find(query, options);
}

findByRoomId(roomId, options) {
const query = {
rid: roomId
Expand Down Expand Up @@ -569,6 +580,34 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base {
return record;
}

createNavigationHistoryWithRoomIdMessageAndUser(roomId, message, user, extraData) {
const type = 'livechat_navigation_history';
const room = RocketChat.models.Rooms.findOneById(roomId, { fields: { sysMes: 1 }});
if ((room != null ? room.sysMes : undefined) === false) {
return;
}
const record = {
t: type,
rid: roomId,
ts: new Date,
msg: message,
u: {
_id: user._id,
username: user.username
},
groupable: false
};

if (RocketChat.settings.get('Message_Read_Receipt_Enabled')) {
record.unread = true;
}

_.extend(record, extraData);

record._id = this.insertOrUpsert(record);
return record;
}

createUserJoinWithRoomIdAndUser(roomId, user, extraData) {
const message = user.username;
return this.createWithTypeRoomIdMessageAndUser('uj', roomId, message, user, extraData);
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-livechat/.app/client/lib/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const api = {
Triggers.processRequest(info);
}

Meteor.call('livechat:pageVisited', visitor.getToken(), info);
Meteor.call('livechat:pageVisited', visitor.getToken(), visitor.getRoom(), info);
},

setCustomField(key, value, overwrite = true) {
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-livechat/.app/client/views/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Template.messages.helpers({
return ChatMessage.find({
rid: visitor.getRoom(),
t: {
'$ne': 't'
'$nin': ['t', 'livechat_navigation_history']
}
}, {
sort: {
Expand Down
3 changes: 2 additions & 1 deletion packages/rocketchat-livechat/.app/imports/client/visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ export default {

this.roomSubscribed = roomId;

const msgTypesNotDisplayed = ['livechat_video_call', 'livechat_navigation_history', 'au'];
msgStream.on(roomId, { token: this.getToken() }, (msg) => {
if (msg.t === 'command') {
Commands[msg.msg] && Commands[msg.msg]();
} else if ((msg.t !== 'livechat_video_call') && (msg.t !== 'au')) {
} else if (!msgTypesNotDisplayed.includes(msg.t)) {
ChatMessage.upsert({ _id: msg._id }, msg);

if (msg.t === 'livechat-close') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this.LivechatMessage = new Mongo.Collection('rocketchat_message');
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ <h4>{{_ "Navigation_History"}}</h4>
{{else}}
<div class="visitor-scroll">
<ul>
{{#each pageVisited}}
<li><a href="{{page.location.href}}" target="_blank" title="{{accessDateTime}}">{{pageTitle}}</a></li>
{{#each pages}}
<li><a href="{{navigation.page.location.href}}" target="_blank" title="{{accessDateTime}}">{{pageTitle}}</a></li>
{{/each}}
</ul>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import moment from 'moment';
const visitorNavigationHistory = new Mongo.Collection('visitor_navigation_history');

Template.visitorNavigation.helpers({
loadingNavigation() {
return !Template.instance().pageVisited.ready();
},

pageVisited() {
pages() {
const room = ChatRoom.findOne({ _id: this.rid }, { fields: { 'v.token': 1 } });

if (room && room.v && room.v.token) {
return LivechatPageVisited.find({ token: room.v.token }, { sort: { ts: -1 } });
if (room) {
return visitorNavigationHistory.find({ rid: room._id }, { sort: { ts: -1 } });
}
},

pageTitle() {
return this.page.title || t('Empty_title');
return this.navigation.page.title || t('Empty_title');
},

accessDateTime() {
Expand Down
16 changes: 16 additions & 0 deletions packages/rocketchat-livechat/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ Meteor.startup(function() {
i18nLabel: 'Send_request_on_agent_message'
});

RocketChat.settings.add('Send_visitor_navigation_history_livechat_webhook_request', false, {
type: 'boolean',
group: 'Livechat',
section: 'CRM_Integration',
i18nLabel: 'Send_visitor_navigation_history_on_request',
i18nDescription: 'Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled',
enableQuery: { _id: 'Livechat_Visitor_navigation_as_a_message', value: true }
});

RocketChat.settings.add('Livechat_webhook_on_capture', false, {
type: 'boolean',
group: 'Livechat',
Expand Down Expand Up @@ -236,6 +245,13 @@ Meteor.startup(function() {
]
});

RocketChat.settings.add('Livechat_Visitor_navigation_as_a_message', false, {
type: 'boolean',
group: 'Livechat',
public: true,
i18nLabel: 'Send_Visitor_navigation_history_as_a_message'
});

RocketChat.settings.add('Livechat_enable_office_hours', false, {
type: 'boolean',
group: 'Livechat',
Expand Down
5 changes: 5 additions & 0 deletions packages/rocketchat-livechat/messageTypes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
RocketChat.MessageTypes.registerType({
id: 'livechat_navigation_history',
system: true
});

RocketChat.MessageTypes.registerType({
id: 'livechat_video_call',
system: true,
Expand Down
1 change: 1 addition & 0 deletions packages/rocketchat-livechat/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ Package.onUse(function(api) {
// models
api.addFiles('server/models/Users.js', 'server');
api.addFiles('server/models/Rooms.js', 'server');
api.addFiles('server/models/Messages.js', 'server');
api.addFiles('server/models/LivechatExternalMessage.js', ['client', 'server']);
api.addFiles('server/models/LivechatCustomField.js', 'server');
api.addFiles('server/models/LivechatDepartment.js', 'server');
Expand Down
19 changes: 16 additions & 3 deletions packages/rocketchat-livechat/server/hooks/sendToCRM.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
const msgNavType = 'livechat_navigation_history';

const sendMessageType = (msgType) => {
const sendNavHistory = RocketChat.settings.get('Livechat_Visitor_navigation_as_a_message') && RocketChat.settings.get('Send_visitor_navigation_history_livechat_webhook_request');

return sendNavHistory && msgType === msgNavType;
};

function sendToCRM(type, room, includeMessages = true) {
const postData = RocketChat.Livechat.getLivechatRoomGuestInfo(room);

Expand All @@ -14,7 +22,7 @@ function sendToCRM(type, room, includeMessages = true) {

if (messages) {
messages.forEach((message) => {
if (message.t) {
if (message.t && !sendMessageType(message.t)) {
return;
}
const msg = {
Expand All @@ -28,6 +36,11 @@ function sendToCRM(type, room, includeMessages = true) {
if (message.u.username !== postData.visitor.username) {
msg.agentId = message.u._id;
}

if (message.t === msgNavType) {
msg.navigation = message.navigation;
}

postData.messages.push(msg);
});
}
Expand Down Expand Up @@ -73,9 +86,9 @@ RocketChat.callbacks.add('afterSaveMessage', function(message, room) {
} else if (!RocketChat.settings.get('Livechat_webhook_on_agent_message')) {
return message;
}

// if the message has a type means it is a special message (like the closing comment), so skips
if (message.t) {
// unless the settings that handle with visitor navigation history are enabled
if (message.t && !sendMessageType(message.t)) {
return message;
}

Expand Down
30 changes: 28 additions & 2 deletions packages/rocketchat-livechat/server/lib/Livechat.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ RocketChat.Livechat = {
throw new Meteor.Error('cannot-access-room');
}

if (newRoom) {
RocketChat.models.Messages.setRoomIdByToken(guest.token, room._id);
}

return { room, newRoom };
},
sendMessage({ guest, message, roomInfo, agent }) {
Expand Down Expand Up @@ -315,9 +319,31 @@ RocketChat.Livechat = {
});
},

savePageHistory(token, pageInfo) {
savePageHistory(token, roomId, pageInfo) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to receive roomId here.. we can rely on RocketChat.models.Rooms.findOneOpenByVisitorToken to get visitor's current room.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sampaiodiego, the RocketChat.models.Rooms.findOneOpenByVisitorToken has a roomId parameter, due to this I changed the savePageHistory to get this parameter.
How can I call the RocketChat.models.Rooms.findOneOpenByVisitorToken method if I don't pass the roomId parameter?
I'm sorry if I'm making a mistake but I think this parameter is necessary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're correct @renatobecker .. I didn't notice RocketChat.models.Rooms.findOneOpenByVisitorToken has a roomId parameter as well. 😉
I'll give this PR a whole review to see how we could still save visitor's navigation history without a room.

if (pageInfo.change === RocketChat.Livechat.historyMonitorType) {
return RocketChat.models.LivechatPageVisited.saveByToken(token, pageInfo);

const user = RocketChat.models.Users.findOneById('rocket.cat');

const pageTitle = pageInfo.title;
const pageUrl = pageInfo.location.href;
const extraData = {
navigation: {
page: pageInfo,
token
}
};

if (!roomId) {
// keep history of unregistered visitors for 1 month
const keepHistoryMiliseconds = 2592000000;
extraData.expireAt = new Date().getTime() + keepHistoryMiliseconds;
}

if (!RocketChat.settings.get('Livechat_Visitor_navigation_as_a_message')) {
extraData._hidden = true;
}

return RocketChat.models.Messages.createNavigationHistoryWithRoomIdMessageAndUser(roomId, `${ TAPi18n.__('New_visitor_navigation') }: ${ pageTitle } - ${ pageUrl }`, user, extraData);
}

return;
Expand Down
4 changes: 2 additions & 2 deletions packages/rocketchat-livechat/server/methods/pageVisited.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Meteor.methods({
'livechat:pageVisited'(token, pageInfo) {
return RocketChat.Livechat.savePageHistory(token, pageInfo);
'livechat:pageVisited'(token, room, pageInfo) {
RocketChat.Livechat.savePageHistory(token, room, pageInfo);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Meteor.methods({
});

// update visited page history to not expire
RocketChat.models.LivechatPageVisited.keepHistoryForToken(token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should keep this behavior. the idea is that page history of unregistered visitors can be deleted (expired), because we track visitor's navigation from the very first interaction.. but if that visitor sends a message then we want to keep his page history "forever"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a problem here.. I tried to keep this behavior, but currently we are sending and storing the navigation history as a message and we have a relation between message and room.
The point is that the method RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser calls another method RocketChat.models.Rooms.incMsgCountById(room._id, 1) and a valid room is required.
So, because of this we can't store messages without a room using this method.
If you could give me an orientation about this it would be nice.

Copy link
Member

@sampaiodiego sampaiodiego Mar 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give this another look, but once we merge #9903 we will not call incMsgCountById anymore.. so we might be able to keep this behavior..
edit: this is not true as well 😞 I've made a confusion with incMsgCountById method. it needs to be there.. what I think we need to do is to create a new method to insert navigation histories and do not call incMsgCountById there..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to keep this behavior, as stated before, we'll have to use a new method to store navigations histories as messages. this new method will use RocketChat.models.Rooms.incMsgCountById only if there is a room opened. please take a special look at this, we'll need an index like that on the messages collection as well.

RocketChat.models.Messages.keepHistoryForToken(token);

return {
userId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Meteor.methods({
throw new Meteor.Error('error-invalid-room', 'Invalid room');
}

const messages = RocketChat.models.Messages.findVisibleByRoomId(rid, { sort: { 'ts' : 1 }});
const messages = RocketChat.models.Messages.findVisibleByRoomIdNotContainingTypes(rid, ['livechat_navigation_history'], { sort: { 'ts' : 1 }});
const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || '');
const footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || '');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Meteor.methods({
});

// update visited page history to not expire
RocketChat.models.LivechatPageVisited.keepHistoryForToken(token);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remember to add this back too =)

RocketChat.models.Messages.keepHistoryForToken(token);

return true;
}
Expand Down
27 changes: 27 additions & 0 deletions packages/rocketchat-livechat/server/models/Messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
RocketChat.models.Messages.keepHistoryForToken = function(token) {
return this.update({
'navigation.token': token,
expireAt: {
$exists: true
}
}, {
$unset: {
expireAt: 1
}
}, {
multi: true
});
};

RocketChat.models.Messages.setRoomIdByToken = function(token, rid) {
return this.update({
'navigation.token': token,
rid: null
}, {
$set: {
rid
}
}, {
multi: true
});
};
Loading