mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 09:09:36 +02:00
Trigger reject tracked changes notification from document-updater
GitOrigin-RevId: 9ac47490d052b3058931ca250f4090e6576f56b2
This commit is contained in:
committed by
Copybot
parent
ad58ec2c79
commit
8f0979d6a2
@@ -29,7 +29,7 @@ const RangesManager = {
|
||||
* @param {string[]} newDocLines - the document lines after the updates were applied
|
||||
* @param {object} opts
|
||||
* @param {boolean} [opts.historyRangesSupport] - whether history ranges support is enabled
|
||||
* @returns {{ newRanges: Ranges, rangesWereCollapsed: boolean, historyUpdates: HistoryUpdate[] }}
|
||||
* @returns {{ newRanges: Ranges, rangesWereCollapsed: boolean, historyUpdates: HistoryUpdate[], removedChangeIds: string[] }}
|
||||
*/
|
||||
applyUpdate(projectId, docId, ranges, updates, newDocLines, opts = {}) {
|
||||
if (ranges == null) {
|
||||
@@ -114,6 +114,9 @@ const RangesManager = {
|
||||
)
|
||||
}
|
||||
const newRanges = RangesManager._getRanges(rangesTracker)
|
||||
const removedChangeIds = Object.keys(
|
||||
rangesTracker.getDirtyState().change.removed
|
||||
)
|
||||
logger.debug(
|
||||
{
|
||||
projectId,
|
||||
@@ -124,7 +127,7 @@ const RangesManager = {
|
||||
},
|
||||
'applied updates to ranges'
|
||||
)
|
||||
return { newRanges, rangesWereCollapsed, historyUpdates }
|
||||
return { newRanges, rangesWereCollapsed, historyUpdates, removedChangeIds }
|
||||
},
|
||||
|
||||
acceptChanges(projectId, docId, changeIds, ranges, lines) {
|
||||
|
||||
@@ -13,6 +13,7 @@ const Errors = require('./Errors')
|
||||
const DocumentManager = require('./DocumentManager')
|
||||
const RangesManager = require('./RangesManager')
|
||||
const SnapshotManager = require('./SnapshotManager')
|
||||
const WebApiManager = require('./WebApiManager')
|
||||
const Profiler = require('./Profiler')
|
||||
const { isInsert, isDelete, getDocLength, computeDocHash } = require('./Utils')
|
||||
const HistoryOTUpdateManager = require('./HistoryOTUpdateManager')
|
||||
@@ -143,15 +144,19 @@ const UpdateManager = {
|
||||
sync: incomingUpdateVersion === previousVersion,
|
||||
})
|
||||
|
||||
const { newRanges, rangesWereCollapsed, historyUpdates } =
|
||||
RangesManager.applyUpdate(
|
||||
projectId,
|
||||
docId,
|
||||
ranges,
|
||||
appliedOps,
|
||||
updatedDocLines,
|
||||
{ historyRangesSupport }
|
||||
)
|
||||
const {
|
||||
newRanges,
|
||||
rangesWereCollapsed,
|
||||
historyUpdates,
|
||||
removedChangeIds,
|
||||
} = RangesManager.applyUpdate(
|
||||
projectId,
|
||||
docId,
|
||||
ranges,
|
||||
appliedOps,
|
||||
updatedDocLines,
|
||||
{ historyRangesSupport }
|
||||
)
|
||||
profile.log('RangesManager.applyUpdate', { sync: true })
|
||||
|
||||
await RedisManager.promises.updateDocument(
|
||||
@@ -197,6 +202,27 @@ const UpdateManager = {
|
||||
}
|
||||
}
|
||||
|
||||
// applyUpdate is not triggered by accept change operations, so any
|
||||
// tracked change removed by the ops we just applied was rejected.
|
||||
if (removedChangeIds.length > 0) {
|
||||
// Fire-and-forget without awaiting because
|
||||
// we hold the doc lock here, and the result of the
|
||||
// notification doesn't affect the update
|
||||
WebApiManager.promises
|
||||
.notifyTrackChangesRejected(
|
||||
projectId,
|
||||
docId,
|
||||
removedChangeIds,
|
||||
update.meta?.user_id
|
||||
)
|
||||
.catch(err => {
|
||||
logger.warn(
|
||||
{ err, projectId, docId, removedChangeIds },
|
||||
'failed to notify web of rejected track changes'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (rangesWereCollapsed) {
|
||||
Metrics.inc('doc-snapshot')
|
||||
logger.debug(
|
||||
|
||||
39
services/document-updater/app/js/WebApiManager.js
Normal file
39
services/document-updater/app/js/WebApiManager.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// @ts-check
|
||||
const Settings = require('@overleaf/settings')
|
||||
const { fetchNothing } = require('@overleaf/fetch-utils')
|
||||
|
||||
const MAX_HTTP_REQUEST_LENGTH = 5000
|
||||
|
||||
/**
|
||||
* @param {string} projectId
|
||||
* @param {string} docId
|
||||
* @param {string[]} rejectedChangeIds
|
||||
* @param {string | undefined} userId
|
||||
*/
|
||||
async function notifyTrackChangesRejected(
|
||||
projectId,
|
||||
docId,
|
||||
rejectedChangeIds,
|
||||
userId
|
||||
) {
|
||||
const url = new URL(
|
||||
`/project/${projectId}/doc/${docId}/changes/reject`,
|
||||
Settings.apis.web.url
|
||||
)
|
||||
|
||||
await fetchNothing(url, {
|
||||
method: 'POST',
|
||||
json: { rejectedChangeIds, userId },
|
||||
basicAuth: {
|
||||
user: Settings.apis.web.user,
|
||||
password: Settings.apis.web.pass,
|
||||
},
|
||||
signal: AbortSignal.timeout(MAX_HTTP_REQUEST_LENGTH),
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
promises: {
|
||||
notifyTrackChangesRejected,
|
||||
},
|
||||
}
|
||||
@@ -258,6 +258,39 @@ describe('RangesManager', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('removedChangeIds', function () {
|
||||
it('should be empty when no tracked changes are removed', function () {
|
||||
const result = this.RangesManager.applyUpdate(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.ranges,
|
||||
this.updates,
|
||||
this.newDocLines
|
||||
)
|
||||
expect(result.removedChangeIds).to.deep.equal([])
|
||||
})
|
||||
|
||||
it('should report the ids of tracked changes that were removed by the update', function () {
|
||||
// original text is "one [two ]three four five"
|
||||
// [] denotes tracked deletes; rejecting it by re-inserting the
|
||||
// matching text drops the tracked change.
|
||||
const ranges = {
|
||||
changes: makeRanges([{ d: 'two ', p: 4 }]),
|
||||
}
|
||||
const updates = makeUpdates([{ i: 'two ', p: 4, u: true }])
|
||||
const newDocLines = ['one two three four five']
|
||||
const result = this.RangesManager.applyUpdate(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
ranges,
|
||||
updates,
|
||||
newDocLines,
|
||||
{ historyRangesSupport: true }
|
||||
)
|
||||
expect(result.removedChangeIds).to.deep.equal(['1'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('with history ranges support', function () {
|
||||
describe('inserts among tracked deletes', function () {
|
||||
beforeEach(function () {
|
||||
|
||||
@@ -74,6 +74,12 @@ describe('UpdateManager', function () {
|
||||
},
|
||||
}
|
||||
|
||||
this.WebApiManager = {
|
||||
promises: {
|
||||
notifyTrackChangesRejected: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
|
||||
this.ProjectHistoryRedisManager = {
|
||||
promises: {
|
||||
queueOps: sinon
|
||||
@@ -94,6 +100,7 @@ describe('UpdateManager', function () {
|
||||
'./DocumentManager': this.DocumentManager,
|
||||
'./RangesManager': this.RangesManager,
|
||||
'./SnapshotManager': this.SnapshotManager,
|
||||
'./WebApiManager': this.WebApiManager,
|
||||
'./Profiler': this.Profiler,
|
||||
'./ProjectHistoryRedisManager': this.ProjectHistoryRedisManager,
|
||||
},
|
||||
@@ -337,6 +344,7 @@ describe('UpdateManager', function () {
|
||||
newRanges: this.updated_ranges,
|
||||
rangesWereCollapsed: false,
|
||||
historyUpdates: this.historyUpdates,
|
||||
removedChangeIds: [],
|
||||
})
|
||||
this.ShareJsUpdateManager.promises.applyUpdate = sinon.stub().resolves({
|
||||
updatedDocLines: this.updatedDocLines,
|
||||
@@ -468,6 +476,7 @@ describe('UpdateManager', function () {
|
||||
newRanges: this.updated_ranges,
|
||||
rangesWereCollapsed: true,
|
||||
historyUpdates: this.historyUpdates,
|
||||
removedChangeIds: [],
|
||||
})
|
||||
await this.UpdateManager.promises.applyUpdate(
|
||||
this.project_id,
|
||||
@@ -524,6 +533,48 @@ describe('UpdateManager', function () {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when tracked changes are rejected', function () {
|
||||
beforeEach(async function () {
|
||||
this.removedChangeIds = ['change-1', 'change-2']
|
||||
this.RangesManager.applyUpdate.returns({
|
||||
newRanges: this.updated_ranges,
|
||||
rangesWereCollapsed: false,
|
||||
historyUpdates: this.historyUpdates,
|
||||
removedChangeIds: this.removedChangeIds,
|
||||
})
|
||||
await this.UpdateManager.promises.applyUpdate(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.update
|
||||
)
|
||||
})
|
||||
|
||||
it('should notify web of the rejected tracked changes', function () {
|
||||
this.WebApiManager.promises.notifyTrackChangesRejected.should.have.been.calledWith(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.removedChangeIds,
|
||||
this.updateMeta.user_id
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when no tracked changes are rejected', function () {
|
||||
beforeEach(async function () {
|
||||
await this.UpdateManager.promises.applyUpdate(
|
||||
this.project_id,
|
||||
this.doc_id,
|
||||
this.update
|
||||
)
|
||||
})
|
||||
|
||||
it('should not notify web', function () {
|
||||
this.WebApiManager.promises.notifyTrackChangesRejected.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('_adjustHistoryUpdatesMetadata', function () {
|
||||
|
||||
Reference in New Issue
Block a user