This repository was archived by the owner on Jun 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 226
[WIP-GSoC-19] Store Livechat sessions on backend side #242
Open
knrt10
wants to merge
17
commits into
RocketChat:develop
Choose a base branch
from
knrt10:iplocation
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
7c0c54e
added method to get location of user
knrt10 55c34b9
added new methods to save data to collection
knrt10 65593b2
asking for user permission for location
knrt10 28675f9
Code fix
knrt10 8f37e07
Added new feature
knrt10 a95236b
Some working Fix
knrt10 c91b895
Added contextual bar
knrt10 00078ab
Active state changed to chatting
knrt10 58c8423
Rebased code
knrt10 dc1b2cc
fixed status changing
knrt10 7918686
User status fix
knrt10 bbdbd24
Added new field to location
knrt10 f8bb330
Rebased code and fixed API
knrt10 34cd17e
Code linted
knrt10 bf85c25
Fixed session without location
knrt10 5281673
Fixed code as per review
knrt10 816e75f
Fixed code as per review
knrt10 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| import queryString from 'query-string'; | ||
| import LivechatClient from '@rocket.chat/sdk/lib/clients/Livechat'; | ||
|
|
||
| const host = window.SERVER_URL | ||
| || queryString.parse(window.location.search).serverUrl | ||
| || (process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null); | ||
| const host = window.SERVER_URL | ||
| || queryString.parse(window.location.search).serverUrl | ||
| || (process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null); | ||
| const useSsl = host && host.match(/^https:/) !== null; | ||
|
|
||
| export const Livechat = new LivechatClient({ host, protocol: 'ddp', useSsl }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,244 @@ | ||
| /* eslint-disable no-lonely-if */ | ||
| /* eslint-disable no-alert */ | ||
| import { getToken } from './main'; | ||
| import { Livechat } from '../api'; | ||
| import store from '../store'; | ||
|
|
||
| const docActivityEvents = ['mousemove', 'mousedown', 'touchend', 'keydown']; | ||
| const token = getToken(); | ||
| let timer; | ||
| let initiated = false; | ||
| const awayTime = 300000; | ||
| let self; | ||
| let oldStatus; | ||
|
|
||
| export const userSessionPresence = { | ||
|
|
||
| init() { | ||
| if (initiated) { | ||
| return; | ||
| } | ||
|
|
||
| initiated = true; | ||
| self = this; | ||
| store.on('change', this.handleStoreChange); | ||
| }, | ||
|
|
||
| reset() { | ||
| initiated = false; | ||
| this.stopEvents(); | ||
| store.off('change', this.handleStoreChange); | ||
| }, | ||
|
|
||
| stopTimer() { | ||
| timer && clearTimeout(timer); | ||
| }, | ||
|
|
||
| startTimer() { | ||
| this.stopTimer(); | ||
| timer = setTimeout(this.setAway, awayTime); | ||
| }, | ||
|
|
||
| handleStoreChange(state) { | ||
| if (!initiated) { | ||
| return; | ||
| } | ||
|
|
||
| const { token } = state; | ||
| token ? self.startEvents() : self.stopEvents(); | ||
| }, | ||
|
|
||
| startEvents() { | ||
| docActivityEvents.forEach((event) => { | ||
| document.addEventListener(event, this.setOnline); | ||
| }); | ||
|
|
||
| window.addEventListener('focus', this.setOnline); | ||
| }, | ||
|
|
||
| stopEvents() { | ||
| docActivityEvents.forEach((event) => { | ||
| document.removeEventListener(event, this.setOnline); | ||
| }); | ||
|
|
||
| window.removeEventListener('focus', this.setOnline); | ||
| this.stopTimer(); | ||
| }, | ||
|
|
||
| async setOnline() { | ||
| self.startTimer(); | ||
| if (oldStatus === 'online') { | ||
| return; | ||
| } | ||
| oldStatus = 'online'; | ||
|
|
||
| await Livechat.updateSessionStatus('online', token); | ||
| }, | ||
|
|
||
| async setAway() { | ||
| self.stopTimer(); | ||
| if (oldStatus === 'away') { | ||
| return; | ||
| } | ||
| oldStatus = 'away'; | ||
| await Livechat.updateSessionStatus('away', token); | ||
| }, | ||
| }; | ||
|
|
||
| const deviceInfo = () => { | ||
| const module = { | ||
| options: [], | ||
| header: [navigator.platform, navigator.userAgent, navigator.appVersion, navigator.vendor, window.opera], | ||
| dataos: [ | ||
| { name: 'Windows Phone', value: 'Windows Phone', version: 'OS' }, | ||
| { name: 'Windows', value: 'Win', version: 'NT' }, | ||
| { name: 'iPhone', value: 'iPhone', version: 'OS' }, | ||
| { name: 'iPad', value: 'iPad', version: 'OS' }, | ||
| { name: 'Kindle', value: 'Silk', version: 'Silk' }, | ||
| { name: 'Android', value: 'Android', version: 'Android' }, | ||
| { name: 'PlayBook', value: 'PlayBook', version: 'OS' }, | ||
| { name: 'BlackBerry', value: 'BlackBerry', version: '/' }, | ||
| { name: 'Macintosh', value: 'Mac', version: 'OS X' }, | ||
| { name: 'Linux', value: 'Linux', version: 'rv' }, | ||
| { name: 'Palm', value: 'Palm', version: 'PalmOS' }, | ||
| ], | ||
| databrowser: [ | ||
| { name: 'Chrome', value: 'Chrome', version: 'Chrome' }, | ||
| { name: 'Firefox', value: 'Firefox', version: 'Firefox' }, | ||
| { name: 'Safari', value: 'Safari', version: 'Version' }, | ||
| { name: 'Internet Explorer', value: 'MSIE', version: 'MSIE' }, | ||
| { name: 'Opera', value: 'Opera', version: 'Opera' }, | ||
| { name: 'BlackBerry', value: 'CLDC', version: 'CLDC' }, | ||
| { name: 'Mozilla', value: 'Mozilla', version: 'Mozilla' }, | ||
| ], | ||
| init() { | ||
| const agent = this.header.join(' '); | ||
| const os = this.matchItem(agent, this.dataos); | ||
| const browser = this.matchItem(agent, this.databrowser); | ||
|
|
||
| return { os, browser }; | ||
| }, | ||
| matchItem(string, data) { | ||
| let i = 0; | ||
| let j = 0; | ||
| let regex; | ||
| let regexv; | ||
| let match; | ||
| let matches; | ||
| let version; | ||
|
|
||
| for (i = 0; i < data.length; i += 1) { | ||
| regex = new RegExp(data[i].value, 'i'); | ||
| match = regex.test(string); | ||
| if (match) { | ||
| regexv = new RegExp(`${ data[i].version }[- /:;]([\\d._]+)`, 'i'); | ||
| matches = string.match(regexv); | ||
| version = ''; | ||
| if (matches) { if (matches[1]) { matches = matches[1]; } } | ||
| if (matches) { | ||
| matches = matches.split(/[._]+/); | ||
| for (j = 0; j < matches.length; j += 1) { | ||
| if (j === 0) { | ||
| version += `${ matches[j] }.`; | ||
| } else { | ||
| version += matches[j]; | ||
| } | ||
| } | ||
| } else { | ||
| version = '0'; | ||
| } | ||
| return { | ||
| name: data[i].name, | ||
| version: parseFloat(version), | ||
| }; | ||
| } | ||
| } | ||
| return { name: 'unknown', version: 0 }; | ||
| }, | ||
| }; | ||
|
|
||
| const info = module.init(); | ||
| return { | ||
| os: info.os.name, | ||
| osVersion: info.os.version, | ||
| browserName: info.browser.name, | ||
| browserVersion: info.browser.version, | ||
| }; | ||
| }; | ||
|
|
||
| export const userSessionWithoutLocation = { | ||
| token, | ||
| deviceInfo: deviceInfo(), | ||
| }; | ||
|
|
||
|
|
||
| /** | ||
| * This is used to convert location to a default type we want to send to server | ||
| * @param {Object} location | ||
| * @returns {Object} | ||
| */ | ||
| const convertLocationToSend = (location) => ( | ||
| { | ||
| countryName: location.country || location.country_name, | ||
| countryCode: location.country_code, | ||
| city: location.city || location.state, | ||
| latitude: location.latitude, | ||
| longitude: location.longitude, | ||
| completLocation: `${ location.country }, ${ location.state }, ${ location.city }`, | ||
| }); | ||
|
|
||
| /** | ||
| * This is used to get location details for user | ||
| * @param {Number} latitude | ||
| * @param {Number} longitude | ||
| * @returns {Object} | ||
| */ | ||
| const sessionInfo = async (latitude, longitude) => { | ||
| const { address } = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${ latitude }&lon=${ longitude }`, { | ||
| mode: 'cors', | ||
| headers: { | ||
| 'Access-Control-Allow-Origin': '*', | ||
| }, | ||
| }).then((res) => res.json()); | ||
|
|
||
| const location = convertLocationToSend(address); | ||
| location.latitude = latitude; | ||
| location.longitude = longitude; | ||
|
|
||
| return { | ||
| location, | ||
| token, | ||
| deviceInfo: deviceInfo(), | ||
| }; | ||
| }; | ||
|
|
||
| /** | ||
| * This function works in following way | ||
| * 1. Asks for user location access | ||
| * 2. If not granted, sets locationAccess in store as false, just send the session information | ||
| * 3. If granted, sets location of user info to DB | ||
| */ | ||
| export const sessionUpdate = async () => { | ||
| if (navigator.geolocation) { | ||
| store.setState({ | ||
| locationAccess: true, | ||
| }); | ||
| navigator.geolocation.getCurrentPosition(async (position) => { | ||
| const userSession = await sessionInfo(position.coords.latitude, position.coords.longitude); | ||
| await Livechat.sendSessionData(userSession); | ||
| userSessionPresence.init(); | ||
| }, async (err) => { | ||
| // This means user has denied location access | ||
| // We need then to confirm location before starting the chat | ||
| // Save state of location access inside store. | ||
| if (err) { | ||
| store.setState({ | ||
| locationAccess: false, | ||
| }); | ||
| userSessionPresence.init(); | ||
| // Send user data without location | ||
| await Livechat.sendSessionData(userSessionWithoutLocation); | ||
| } | ||
| }); | ||
| } | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ export class RegisterContainer extends Component { | |
| await dispatch({ loading: true, department }); | ||
| try { | ||
| await Livechat.grantVisitor({ visitor: { ...fields, token } }); | ||
| await Livechat.updateVisitorSessionOnRegister({ visitor: { ...fields, token } }); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just one method to update the livechat session? |
||
| parentCall('callback', ['pre-chat-form-submit', fields]); | ||
| await loadConfig(); | ||
| } finally { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.