2020-03-03 08:59:09 -05:00
|
|
|
const { expect } = require('chai')
|
2019-05-29 05:21:06 -04:00
|
|
|
const sinon = require('sinon')
|
|
|
|
const SandboxedModule = require('sandboxed-module')
|
2020-03-04 04:38:40 -05:00
|
|
|
const { ObjectId } = require('mongodb')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2020-03-03 08:59:09 -05:00
|
|
|
const MODULE_PATH = '../../../../app/src/Features/History/HistoryManager'
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('HistoryManager', function () {
|
|
|
|
beforeEach(function () {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.user_id = 'user-id-123'
|
|
|
|
this.AuthenticationController = {
|
2021-04-27 03:52:58 -04:00
|
|
|
getLoggedInUserId: sinon.stub().returns(this.user_id),
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2020-03-03 08:59:09 -05:00
|
|
|
this.request = {
|
2020-03-04 04:38:40 -05:00
|
|
|
post: sinon.stub(),
|
2021-04-27 03:52:58 -04:00
|
|
|
delete: sinon.stub().resolves(),
|
2020-03-03 08:59:09 -05:00
|
|
|
}
|
2020-03-04 04:38:40 -05:00
|
|
|
this.projectHistoryUrl = 'http://project_history.example.com'
|
2021-01-14 08:56:36 -05:00
|
|
|
this.v1HistoryUrl = 'http://v1_history.example.com'
|
|
|
|
this.v1HistoryUser = 'system'
|
|
|
|
this.v1HistoryPassword = 'verysecret'
|
2020-03-03 08:59:09 -05:00
|
|
|
this.settings = {
|
|
|
|
apis: {
|
|
|
|
trackchanges: {
|
|
|
|
enabled: false,
|
2021-04-27 03:52:58 -04:00
|
|
|
url: 'http://trackchanges.example.com',
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
project_history: {
|
2021-04-27 03:52:58 -04:00
|
|
|
url: this.projectHistoryUrl,
|
2021-01-14 08:56:36 -05:00
|
|
|
},
|
|
|
|
v1_history: {
|
|
|
|
url: this.v1HistoryUrl,
|
|
|
|
user: this.v1HistoryUser,
|
2021-04-27 03:52:58 -04:00
|
|
|
pass: this.v1HistoryPassword,
|
|
|
|
},
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
this.UserGetter = {
|
|
|
|
promises: {
|
|
|
|
getUsersByV1Ids: sinon.stub(),
|
2021-04-27 03:52:58 -04:00
|
|
|
getUsers: sinon.stub(),
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
this.HistoryManager = SandboxedModule.require(MODULE_PATH, {
|
2019-05-29 05:21:06 -04:00
|
|
|
requires: {
|
2020-03-03 08:59:09 -05:00
|
|
|
'request-promise-native': this.request,
|
|
|
|
'settings-sharelatex': this.settings,
|
2021-04-27 03:52:58 -04:00
|
|
|
'../User/UserGetter': this.UserGetter,
|
|
|
|
},
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('initializeProject', function () {
|
|
|
|
describe('with project history enabled', function () {
|
|
|
|
beforeEach(function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
this.settings.apis.project_history.initializeHistoryForNewProjects = true
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('project history returns a successful response', function () {
|
|
|
|
beforeEach(async function () {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.overleaf_id = 1234
|
2020-03-03 08:59:09 -05:00
|
|
|
this.request.post.resolves(
|
|
|
|
JSON.stringify({ project: { id: this.overleaf_id } })
|
|
|
|
)
|
|
|
|
this.result = await this.HistoryManager.promises.initializeProject()
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should call the project history api', function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
this.request.post
|
2019-05-29 05:21:06 -04:00
|
|
|
.calledWith({
|
2021-04-27 03:52:58 -04:00
|
|
|
url: `${this.settings.apis.project_history.url}/project`,
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
.should.equal(true)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should return the overleaf id', function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
expect(this.result).to.deep.equal({ overleaf_id: this.overleaf_id })
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('project history returns a response without the project id', function () {
|
|
|
|
it('should throw an error', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
this.request.post.resolves(JSON.stringify({ project: {} }))
|
|
|
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
|
|
|
.rejected
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('project history errors', function () {
|
|
|
|
it('should propagate the error', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
this.request.post.rejects(new Error('problem connecting'))
|
|
|
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
|
|
|
.rejected
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('with project history disabled', function () {
|
|
|
|
it('should return without errors', async function () {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.settings.apis.project_history.initializeHistoryForNewProjects = false
|
2020-03-03 08:59:09 -05:00
|
|
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
|
|
|
.fulfilled
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('injectUserDetails', function () {
|
|
|
|
beforeEach(function () {
|
2019-05-29 05:21:06 -04:00
|
|
|
this.user1 = {
|
|
|
|
_id: (this.user_id1 = '123456'),
|
|
|
|
first_name: 'Jane',
|
|
|
|
last_name: 'Doe',
|
2019-07-29 05:47:44 -04:00
|
|
|
email: 'jane@example.com',
|
2021-04-27 03:52:58 -04:00
|
|
|
overleaf: { id: 5011 },
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
this.user1_view = {
|
|
|
|
id: this.user_id1,
|
|
|
|
first_name: 'Jane',
|
|
|
|
last_name: 'Doe',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'jane@example.com',
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
this.user2 = {
|
|
|
|
_id: (this.user_id2 = 'abcdef'),
|
|
|
|
first_name: 'John',
|
|
|
|
last_name: 'Doe',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'john@example.com',
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
this.user2_view = {
|
|
|
|
id: this.user_id2,
|
|
|
|
first_name: 'John',
|
|
|
|
last_name: 'Doe',
|
2021-04-27 03:52:58 -04:00
|
|
|
email: 'john@example.com',
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2020-03-03 08:59:09 -05:00
|
|
|
this.UserGetter.promises.getUsersByV1Ids.resolves([this.user1])
|
|
|
|
this.UserGetter.promises.getUsers.resolves([this.user1, this.user2])
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('with a diff', function () {
|
|
|
|
it('should turn user_ids into user objects', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
|
|
|
diff: [
|
|
|
|
{
|
|
|
|
i: 'foo',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id1],
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
i: 'bar',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id2],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2020-03-03 08:59:09 -05:00
|
|
|
})
|
|
|
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
|
|
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should handle v1 user ids', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
|
|
|
diff: [
|
|
|
|
{
|
|
|
|
i: 'foo',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [5011],
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
i: 'bar',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id2],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2020-03-03 08:59:09 -05:00
|
|
|
})
|
|
|
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
|
|
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
2019-07-29 05:47:44 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should leave user objects', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
|
|
|
diff: [
|
|
|
|
{
|
|
|
|
i: 'foo',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user1_view],
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
i: 'bar',
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id2],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2020-03-03 08:59:09 -05:00
|
|
|
})
|
|
|
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
|
|
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
2020-03-05 11:36:12 -05:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should handle a binary diff marker', async function () {
|
2020-03-05 11:36:12 -05:00
|
|
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
2021-04-27 03:52:58 -04:00
|
|
|
diff: { binary: true },
|
2020-03-05 11:36:12 -05:00
|
|
|
})
|
|
|
|
expect(diff.diff.binary).to.be.true
|
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('with a list of updates', function () {
|
|
|
|
it('should turn user_ids into user objects', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
const updates = await this.HistoryManager.promises.injectUserDetails({
|
|
|
|
updates: [
|
|
|
|
{
|
|
|
|
fromV: 5,
|
|
|
|
toV: 8,
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id1],
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
fromV: 4,
|
|
|
|
toV: 5,
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id2],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2020-03-03 08:59:09 -05:00
|
|
|
})
|
|
|
|
expect(updates.updates[0].meta.users).to.deep.equal([this.user1_view])
|
|
|
|
expect(updates.updates[1].meta.users).to.deep.equal([this.user2_view])
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should leave user objects', async function () {
|
2020-03-03 08:59:09 -05:00
|
|
|
const updates = await this.HistoryManager.promises.injectUserDetails({
|
|
|
|
updates: [
|
|
|
|
{
|
|
|
|
fromV: 5,
|
|
|
|
toV: 8,
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user1_view],
|
|
|
|
},
|
2020-03-03 08:59:09 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
fromV: 4,
|
|
|
|
toV: 5,
|
|
|
|
meta: {
|
2021-04-27 03:52:58 -04:00
|
|
|
users: [this.user_id2],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2020-03-03 08:59:09 -05:00
|
|
|
})
|
|
|
|
expect(updates.updates[0].meta.users).to.deep.equal([this.user1_view])
|
|
|
|
expect(updates.updates[1].meta.users).to.deep.equal([this.user2_view])
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2020-03-04 04:38:40 -05:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
describe('deleteProject', function () {
|
2021-01-14 08:56:36 -05:00
|
|
|
const projectId = new ObjectId()
|
|
|
|
const historyId = new ObjectId()
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
beforeEach(async function () {
|
2021-01-14 08:56:36 -05:00
|
|
|
await this.HistoryManager.promises.deleteProject(projectId, historyId)
|
|
|
|
})
|
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should call the project-history service', async function () {
|
2020-03-04 04:38:40 -05:00
|
|
|
expect(this.request.delete).to.have.been.calledWith(
|
|
|
|
`${this.projectHistoryUrl}/project/${projectId}`
|
|
|
|
)
|
|
|
|
})
|
2021-01-14 08:56:36 -05:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
it('should call the v1-history service', async function () {
|
2021-01-14 08:56:36 -05:00
|
|
|
expect(this.request.delete).to.have.been.calledWith({
|
|
|
|
url: `${this.v1HistoryUrl}/projects/${historyId}`,
|
|
|
|
auth: {
|
|
|
|
user: this.v1HistoryUser,
|
2021-04-27 03:52:58 -04:00
|
|
|
pass: this.v1HistoryPassword,
|
|
|
|
},
|
2021-01-14 08:56:36 -05:00
|
|
|
})
|
|
|
|
})
|
2020-03-04 04:38:40 -05:00
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|