Merge pull request #4655 from overleaf/jel-gallery-event

Fix onclick event propagation

GitOrigin-RevId: bfcc3840e1768ed0f91e5fefbaee1738e36f6752
This commit is contained in:
June Kelly 2021-08-11 09:50:38 +01:00 committed by Copybot
parent 0acd81dfc0
commit 8b9d202518
4 changed files with 40 additions and 24 deletions

View file

@ -32,6 +32,7 @@ module.exports = {
} }
const userId = const userId =
SessionManager.getLoggedInUserId(req.session) || req.sessionID SessionManager.getLoggedInUserId(req.session) || req.sessionID
delete req.body._csrf
AnalyticsManager.recordEvent(userId, req.params.event, req.body) AnalyticsManager.recordEvent(userId, req.params.event, req.body)
res.sendStatus(202) res.sendStatus(202)
}, },

View file

@ -1,4 +1,3 @@
import { postJSON } from './fetch-json'
import sessionStorage from '../infrastructure/session-storage' import sessionStorage from '../infrastructure/session-storage'
const CACHE_KEY = 'mbEvents' const CACHE_KEY = 'mbEvents'
@ -10,11 +9,7 @@ export function send(category, action, label, value) {
} }
export function sendMB(key, segmentation = {}) { export function sendMB(key, segmentation = {}) {
postJSON(`/event/${key}`, { body: segmentation, keepalive: true }).catch( sendBeacon(key, segmentation)
() => {
// ignore errors
}
)
} }
export function sendMBOnce(key, segmentation = {}) { export function sendMBOnce(key, segmentation = {}) {
@ -39,3 +34,13 @@ export function sendMBSampled(key, body = {}, rate = 0.01) {
sendMB(key, body) sendMB(key, body)
} }
} }
function sendBeacon(key, data) {
if (!navigator || !navigator.sendBeacon) return
data._csrf = window.csrfToken
const blob = new Blob([JSON.stringify(data)], {
type: 'application/json; charset=UTF-8',
})
navigator.sendBeacon(`/event/${key}`, blob)
}

View file

@ -15,6 +15,7 @@
import moment from 'moment' import moment from 'moment'
import App from '../base' import App from '../base'
import '../modules/localStorage' import '../modules/localStorage'
import { sendMB } from '../infrastructure/event-tracking'
const CACHE_KEY = 'mbEvents' const CACHE_KEY = 'mbEvents'
// keep track of how many heartbeats we've sent so we can calculate how // keep track of how many heartbeats we've sent so we can calculate how
@ -89,21 +90,7 @@ App.factory('eventTracking', function ($http, localStorage) {
return (nextHeartbeat = moment().add(backoffSecs, 'seconds').toDate()) return (nextHeartbeat = moment().add(backoffSecs, 'seconds').toDate())
}, },
sendMB(key, segmentation) { sendMB,
if (segmentation == null) {
segmentation = {}
}
fetch(`/event/${key}`, {
method: 'POST',
body: JSON.stringify(segmentation),
keepalive: true,
headers: {
'X-CSRF-Token': window.csrfToken,
'Content-Type': 'application/json',
Accept: 'application/json',
},
})
},
sendMBSampled(key, segmentation, rate = 0.01) { sendMBSampled(key, segmentation, rate = 0.01) {
if (Math.random() < rate) { if (Math.random() < rate) {

View file

@ -61,21 +61,28 @@ describe('AnalyticsController', function () {
describe('recordEvent', function () { describe('recordEvent', function () {
beforeEach(function () { beforeEach(function () {
const body = {
foo: 'stuff',
_csrf: 'atoken123',
}
this.req = { this.req = {
params: { params: {
event: 'i_did_something', event: 'i_did_something',
}, },
body: 'stuff', body,
sessionID: 'sessionIDHere', sessionID: 'sessionIDHere',
session: {}, session: {},
} }
this.expectedData = Object.assign({}, body)
delete this.expectedData._csrf
}) })
it('should use the user_id', function (done) { it('should use the user_id', function (done) {
this.SessionManager.getLoggedInUserId.returns('1234') this.SessionManager.getLoggedInUserId.returns('1234')
this.controller.recordEvent(this.req, this.res) this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent this.AnalyticsManager.recordEvent
.calledWith('1234', this.req.params.event, this.req.body) .calledWith('1234', this.req.params.event, this.expectedData)
.should.equal(true) .should.equal(true)
done() done()
}) })
@ -83,7 +90,23 @@ describe('AnalyticsController', function () {
it('should use the session id', function (done) { it('should use the session id', function (done) {
this.controller.recordEvent(this.req, this.res) this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent this.AnalyticsManager.recordEvent
.calledWith(this.req.sessionID, this.req.params.event, this.req.body) .calledWith(
this.req.sessionID,
this.req.params.event,
this.expectedData
)
.should.equal(true)
done()
})
it('should remove the CSRF token before sending to the manager', function (done) {
this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent
.calledWith(
this.req.sessionID,
this.req.params.event,
this.expectedData
)
.should.equal(true) .should.equal(true)
done() done()
}) })