mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #2647 from overleaf/em-promisify-history-manager
Promisify HistoryManager GitOrigin-RevId: cbf946a7d61f7f57bad03e4c83184c6decd91027
This commit is contained in:
parent
1f89083ab2
commit
d8d1bdd461
2 changed files with 281 additions and 450 deletions
|
@ -1,224 +1,143 @@
|
||||||
/* eslint-disable
|
const { callbackify } = require('util')
|
||||||
camelcase,
|
const request = require('request-promise-native')
|
||||||
handle-callback-err,
|
|
||||||
max-len,
|
|
||||||
no-unused-vars,
|
|
||||||
*/
|
|
||||||
// TODO: This file was created by bulk-decaffeinate.
|
|
||||||
// Fix any style issues and re-enable lint.
|
|
||||||
/*
|
|
||||||
* decaffeinate suggestions:
|
|
||||||
* DS101: Remove unnecessary use of Array.from
|
|
||||||
* DS102: Remove unnecessary code created because of implicit returns
|
|
||||||
* DS103: Rewrite code to no longer use __guard__
|
|
||||||
* DS207: Consider shorter variations of null checks
|
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
||||||
*/
|
|
||||||
const request = require('request')
|
|
||||||
const settings = require('settings-sharelatex')
|
const settings = require('settings-sharelatex')
|
||||||
const async = require('async')
|
const OError = require('@overleaf/o-error')
|
||||||
const UserGetter = require('../User/UserGetter')
|
const UserGetter = require('../User/UserGetter')
|
||||||
const { promisifyAll } = require('../../util/promises')
|
|
||||||
|
|
||||||
const HistoryManager = {
|
module.exports = {
|
||||||
initializeProject(callback) {
|
initializeProject: callbackify(initializeProject),
|
||||||
if (callback == null) {
|
flushProject: callbackify(flushProject),
|
||||||
callback = function(error, history_id) {}
|
resyncProject: callbackify(resyncProject),
|
||||||
}
|
injectUserDetails: callbackify(injectUserDetails),
|
||||||
if (
|
promises: {
|
||||||
!(settings.apis.project_history != null
|
initializeProject,
|
||||||
? settings.apis.project_history.initializeHistoryForNewProjects
|
flushProject,
|
||||||
: undefined)
|
resyncProject,
|
||||||
) {
|
injectUserDetails
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
return request.post(
|
|
||||||
{
|
|
||||||
url: `${settings.apis.project_history.url}/project`
|
|
||||||
},
|
|
||||||
function(error, res, body) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
let project
|
|
||||||
try {
|
|
||||||
project = JSON.parse(body)
|
|
||||||
} catch (error1) {
|
|
||||||
error = error1
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const overleaf_id = __guard__(
|
|
||||||
project != null ? project.project : undefined,
|
|
||||||
x => x.id
|
|
||||||
)
|
|
||||||
if (!overleaf_id) {
|
|
||||||
error = new Error('project-history did not provide an id', project)
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(null, { overleaf_id })
|
|
||||||
} else {
|
|
||||||
error = new Error(
|
|
||||||
`project-history returned a non-success status code: ${
|
|
||||||
res.statusCode
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
flushProject(project_id, callback) {
|
|
||||||
if (callback == null) {
|
|
||||||
callback = function(error) {}
|
|
||||||
}
|
|
||||||
return request.post(
|
|
||||||
{
|
|
||||||
url: `${settings.apis.project_history.url}/project/${project_id}/flush`
|
|
||||||
},
|
|
||||||
function(error, res, body) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
return callback()
|
|
||||||
} else {
|
|
||||||
error = new Error(
|
|
||||||
`project-history returned a non-success status code: ${
|
|
||||||
res.statusCode
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
resyncProject(project_id, callback) {
|
|
||||||
if (callback == null) {
|
|
||||||
callback = function(error) {}
|
|
||||||
}
|
|
||||||
return request.post(
|
|
||||||
{
|
|
||||||
url: `${settings.apis.project_history.url}/project/${project_id}/resync`
|
|
||||||
},
|
|
||||||
function(error, res, body) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
return callback()
|
|
||||||
} else {
|
|
||||||
error = new Error(
|
|
||||||
`project-history returned a non-success status code: ${
|
|
||||||
res.statusCode
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
injectUserDetails(data, callback) {
|
|
||||||
// data can be either:
|
|
||||||
// {
|
|
||||||
// diff: [{
|
|
||||||
// i: "foo",
|
|
||||||
// meta: {
|
|
||||||
// users: ["user_id", v1_user_id, ...]
|
|
||||||
// ...
|
|
||||||
// }
|
|
||||||
// }, ...]
|
|
||||||
// }
|
|
||||||
// or
|
|
||||||
// {
|
|
||||||
// updates: [{
|
|
||||||
// pathnames: ["main.tex"]
|
|
||||||
// meta: {
|
|
||||||
// users: ["user_id", v1_user_id, ...]
|
|
||||||
// ...
|
|
||||||
// },
|
|
||||||
// ...
|
|
||||||
// }, ...]
|
|
||||||
// }
|
|
||||||
// Either way, the top level key points to an array of objects with a meta.users property
|
|
||||||
// that we need to replace user_ids with populated user objects.
|
|
||||||
// Note that some entries in the users arrays may be v1 ids returned by the v1 history
|
|
||||||
// service. v1 ids will be `numbers`
|
|
||||||
let entry, user
|
|
||||||
if (callback == null) {
|
|
||||||
callback = function(error, data_with_users) {}
|
|
||||||
}
|
|
||||||
let user_ids = new Set()
|
|
||||||
let v1_user_ids = new Set()
|
|
||||||
for (entry of Array.from(data.diff || data.updates || [])) {
|
|
||||||
for (user of Array.from(
|
|
||||||
(entry.meta != null ? entry.meta.users : undefined) || []
|
|
||||||
)) {
|
|
||||||
if (typeof user === 'string') {
|
|
||||||
user_ids.add(user)
|
|
||||||
} else if (typeof user === 'number') {
|
|
||||||
v1_user_ids.add(user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
user_ids = Array.from(user_ids)
|
|
||||||
v1_user_ids = Array.from(v1_user_ids)
|
|
||||||
const projection = { first_name: 1, last_name: 1, email: 1 }
|
|
||||||
return UserGetter.getUsers(user_ids, projection, function(
|
|
||||||
error,
|
|
||||||
users_array
|
|
||||||
) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(error)
|
|
||||||
}
|
|
||||||
const v1_query = { 'overleaf.id': v1_user_ids }
|
|
||||||
const users = {}
|
|
||||||
for (user of Array.from(users_array || [])) {
|
|
||||||
users[user._id.toString()] = HistoryManager._userView(user)
|
|
||||||
}
|
|
||||||
projection.overleaf = 1
|
|
||||||
UserGetter.getUsersByV1Ids(
|
|
||||||
v1_user_ids,
|
|
||||||
projection,
|
|
||||||
(error, v1_identified_users_array) => {
|
|
||||||
for (user of Array.from(v1_identified_users_array || [])) {
|
|
||||||
users[user.overleaf.id] = HistoryManager._userView(user)
|
|
||||||
}
|
|
||||||
for (entry of Array.from(data.diff || data.updates || [])) {
|
|
||||||
if (entry.meta != null) {
|
|
||||||
entry.meta.users = (
|
|
||||||
(entry.meta != null ? entry.meta.users : undefined) || []
|
|
||||||
).map(function(user) {
|
|
||||||
if (typeof user === 'string' || typeof user === 'number') {
|
|
||||||
return users[user]
|
|
||||||
} else {
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return callback(null, data)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
_userView(user) {
|
|
||||||
const { _id, first_name, last_name, email } = user
|
|
||||||
return { first_name, last_name, email, id: _id }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function __guard__(value, transform) {
|
|
||||||
return typeof value !== 'undefined' && value !== null
|
async function initializeProject() {
|
||||||
? transform(value)
|
if (
|
||||||
: undefined
|
!(
|
||||||
|
settings.apis.project_history &&
|
||||||
|
settings.apis.project_history.initializeHistoryForNewProjects
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const body = await request.post({
|
||||||
|
url: `${settings.apis.project_history.url}/project`
|
||||||
|
})
|
||||||
|
const project = JSON.parse(body)
|
||||||
|
const overleafId = project && project.project && project.project.id
|
||||||
|
if (!overleafId) {
|
||||||
|
throw new Error('project-history did not provide an id', project)
|
||||||
|
}
|
||||||
|
return { overleaf_id: overleafId }
|
||||||
|
} catch (err) {
|
||||||
|
throw new OError({
|
||||||
|
message: 'failed to initialize project history'
|
||||||
|
}).withCause(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryManager.promises = promisifyAll(HistoryManager, { without: '_userView' })
|
async function flushProject(projectId) {
|
||||||
module.exports = HistoryManager
|
try {
|
||||||
|
await request.post({
|
||||||
|
url: `${settings.apis.project_history.url}/project/${projectId}/flush`
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
throw new OError({
|
||||||
|
message: 'failed to flush project to project history',
|
||||||
|
info: { projectId }
|
||||||
|
}).withCause(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resyncProject(projectId) {
|
||||||
|
try {
|
||||||
|
await request.post({
|
||||||
|
url: `${settings.apis.project_history.url}/project/${projectId}/resync`
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
throw new OError({
|
||||||
|
message: 'failed to resync project history',
|
||||||
|
info: { projectId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function injectUserDetails(data) {
|
||||||
|
// data can be either:
|
||||||
|
// {
|
||||||
|
// diff: [{
|
||||||
|
// i: "foo",
|
||||||
|
// meta: {
|
||||||
|
// users: ["user_id", v1_user_id, ...]
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
// }, ...]
|
||||||
|
// }
|
||||||
|
// or
|
||||||
|
// {
|
||||||
|
// updates: [{
|
||||||
|
// pathnames: ["main.tex"]
|
||||||
|
// meta: {
|
||||||
|
// users: ["user_id", v1_user_id, ...]
|
||||||
|
// ...
|
||||||
|
// },
|
||||||
|
// ...
|
||||||
|
// }, ...]
|
||||||
|
// }
|
||||||
|
// Either way, the top level key points to an array of objects with a meta.users property
|
||||||
|
// that we need to replace user_ids with populated user objects.
|
||||||
|
// Note that some entries in the users arrays may be v1 ids returned by the v1 history
|
||||||
|
// service. v1 ids will be `numbers`
|
||||||
|
let userIds = new Set()
|
||||||
|
let v1UserIds = new Set()
|
||||||
|
for (const entry of data.diff || data.updates || []) {
|
||||||
|
for (const user of (entry.meta && entry.meta.users) || []) {
|
||||||
|
if (typeof user === 'string') {
|
||||||
|
userIds.add(user)
|
||||||
|
} else if (typeof user === 'number') {
|
||||||
|
v1UserIds.add(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userIds = Array.from(userIds)
|
||||||
|
v1UserIds = Array.from(v1UserIds)
|
||||||
|
const projection = { first_name: 1, last_name: 1, email: 1 }
|
||||||
|
const usersArray = await UserGetter.promises.getUsers(userIds, projection)
|
||||||
|
const users = {}
|
||||||
|
for (const user of usersArray) {
|
||||||
|
users[user._id.toString()] = _userView(user)
|
||||||
|
}
|
||||||
|
projection.overleaf = 1
|
||||||
|
const v1IdentifiedUsersArray = await UserGetter.promises.getUsersByV1Ids(
|
||||||
|
v1UserIds,
|
||||||
|
projection
|
||||||
|
)
|
||||||
|
for (const user of v1IdentifiedUsersArray) {
|
||||||
|
users[user.overleaf.id] = _userView(user)
|
||||||
|
}
|
||||||
|
for (const entry of data.diff || data.updates || []) {
|
||||||
|
if (entry.meta != null) {
|
||||||
|
entry.meta.users = ((entry.meta && entry.meta.users) || []).map(user => {
|
||||||
|
if (typeof user === 'string' || typeof user === 'number') {
|
||||||
|
return users[user]
|
||||||
|
} else {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
function _userView(user) {
|
||||||
|
const { _id, first_name: firstName, last_name: lastName, email } = user
|
||||||
|
return { first_name: firstName, last_name: lastName, email, id: _id }
|
||||||
|
}
|
||||||
|
|
|
@ -1,45 +1,45 @@
|
||||||
/* eslint-disable
|
const { expect } = require('chai')
|
||||||
max-len,
|
|
||||||
no-return-assign,
|
|
||||||
*/
|
|
||||||
// TODO: This file was created by bulk-decaffeinate.
|
|
||||||
// Fix any style issues and re-enable lint.
|
|
||||||
/*
|
|
||||||
* decaffeinate suggestions:
|
|
||||||
* DS102: Remove unnecessary code created because of implicit returns
|
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
||||||
*/
|
|
||||||
const chai = require('chai')
|
|
||||||
chai.should()
|
|
||||||
const { expect } = chai
|
|
||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const modulePath = '../../../../app/src/Features/History/HistoryManager'
|
|
||||||
const SandboxedModule = require('sandboxed-module')
|
const SandboxedModule = require('sandboxed-module')
|
||||||
|
|
||||||
|
const MODULE_PATH = '../../../../app/src/Features/History/HistoryManager'
|
||||||
|
|
||||||
describe('HistoryManager', function() {
|
describe('HistoryManager', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.callback = sinon.stub()
|
|
||||||
this.user_id = 'user-id-123'
|
this.user_id = 'user-id-123'
|
||||||
this.AuthenticationController = {
|
this.AuthenticationController = {
|
||||||
getLoggedInUserId: sinon.stub().returns(this.user_id)
|
getLoggedInUserId: sinon.stub().returns(this.user_id)
|
||||||
}
|
}
|
||||||
this.HistoryManager = SandboxedModule.require(modulePath, {
|
this.request = {
|
||||||
|
post: sinon.stub()
|
||||||
|
}
|
||||||
|
this.settings = {
|
||||||
|
apis: {
|
||||||
|
trackchanges: {
|
||||||
|
enabled: false,
|
||||||
|
url: 'http://trackchanges.example.com'
|
||||||
|
},
|
||||||
|
project_history: {
|
||||||
|
url: 'http://project_history.example.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UserGetter = {
|
||||||
|
promises: {
|
||||||
|
getUsersByV1Ids: sinon.stub(),
|
||||||
|
getUsers: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.HistoryManager = SandboxedModule.require(MODULE_PATH, {
|
||||||
globals: {
|
globals: {
|
||||||
console: console
|
console: console
|
||||||
},
|
},
|
||||||
requires: {
|
requires: {
|
||||||
request: (this.request = sinon.stub()),
|
'request-promise-native': this.request,
|
||||||
'settings-sharelatex': (this.settings = {}),
|
'settings-sharelatex': this.settings,
|
||||||
'../User/UserGetter': (this.UserGetter = {})
|
'../User/UserGetter': this.UserGetter
|
||||||
}
|
|
||||||
})
|
|
||||||
return (this.settings.apis = {
|
|
||||||
trackchanges: {
|
|
||||||
enabled: false,
|
|
||||||
url: 'http://trackchanges.example.com'
|
|
||||||
},
|
|
||||||
project_history: {
|
|
||||||
url: 'http://project_history.example.com'
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -47,101 +47,53 @@ describe('HistoryManager', function() {
|
||||||
describe('initializeProject', function() {
|
describe('initializeProject', function() {
|
||||||
describe('with project history enabled', function() {
|
describe('with project history enabled', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
return (this.settings.apis.project_history.initializeHistoryForNewProjects = true)
|
this.settings.apis.project_history.initializeHistoryForNewProjects = true
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('project history returns a successful response', function() {
|
describe('project history returns a successful response', function() {
|
||||||
beforeEach(function() {
|
beforeEach(async function() {
|
||||||
this.overleaf_id = 1234
|
this.overleaf_id = 1234
|
||||||
this.res = { statusCode: 200 }
|
this.request.post.resolves(
|
||||||
this.body = JSON.stringify({ project: { id: this.overleaf_id } })
|
JSON.stringify({ project: { id: this.overleaf_id } })
|
||||||
this.request.post = sinon
|
)
|
||||||
.stub()
|
this.result = await this.HistoryManager.promises.initializeProject()
|
||||||
.callsArgWith(1, null, this.res, this.body)
|
|
||||||
|
|
||||||
return this.HistoryManager.initializeProject(this.callback)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should call the project history api', function() {
|
it('should call the project history api', function() {
|
||||||
return this.request.post
|
this.request.post
|
||||||
.calledWith({
|
.calledWith({
|
||||||
url: `${this.settings.apis.project_history.url}/project`
|
url: `${this.settings.apis.project_history.url}/project`
|
||||||
})
|
})
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return the callback with the overleaf id', function() {
|
it('should return the overleaf id', function() {
|
||||||
return this.callback
|
expect(this.result).to.deep.equal({ overleaf_id: this.overleaf_id })
|
||||||
.calledWithExactly(null, { overleaf_id: this.overleaf_id })
|
|
||||||
.should.equal(true)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('project history returns a response without the project id', function() {
|
describe('project history returns a response without the project id', function() {
|
||||||
beforeEach(function() {
|
it('should throw an error', async function() {
|
||||||
this.res = { statusCode: 200 }
|
this.request.post.resolves(JSON.stringify({ project: {} }))
|
||||||
this.body = JSON.stringify({ project: {} })
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
||||||
this.request.post = sinon
|
.rejected
|
||||||
.stub()
|
|
||||||
.callsArgWith(1, null, this.res, this.body)
|
|
||||||
|
|
||||||
return this.HistoryManager.initializeProject(this.callback)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return the callback with an error', function() {
|
|
||||||
return this.callback
|
|
||||||
.calledWith(
|
|
||||||
sinon.match.has(
|
|
||||||
'message',
|
|
||||||
'project-history did not provide an id'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.should.equal(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('project history returns a unsuccessful response', function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
this.res = { statusCode: 404 }
|
|
||||||
this.request.post = sinon.stub().callsArgWith(1, null, this.res)
|
|
||||||
|
|
||||||
return this.HistoryManager.initializeProject(this.callback)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return the callback with an error', function() {
|
|
||||||
return this.callback
|
|
||||||
.calledWith(
|
|
||||||
sinon.match.has(
|
|
||||||
'message',
|
|
||||||
'project-history returned a non-success status code: 404'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.should.equal(true)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('project history errors', function() {
|
describe('project history errors', function() {
|
||||||
beforeEach(function() {
|
it('should propagate the error', async function() {
|
||||||
this.error = sinon.stub()
|
this.request.post.rejects(new Error('problem connecting'))
|
||||||
this.request.post = sinon.stub().callsArgWith(1, this.error)
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
||||||
|
.rejected
|
||||||
return this.HistoryManager.initializeProject(this.callback)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return the callback with the error', function() {
|
|
||||||
return this.callback.calledWithExactly(this.error).should.equal(true)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with project history disabled', function() {
|
describe('with project history disabled', function() {
|
||||||
beforeEach(function() {
|
it('should return without errors', async function() {
|
||||||
this.settings.apis.project_history.initializeHistoryForNewProjects = false
|
this.settings.apis.project_history.initializeHistoryForNewProjects = false
|
||||||
return this.HistoryManager.initializeProject(this.callback)
|
await expect(this.HistoryManager.promises.initializeProject()).to.be
|
||||||
})
|
.fulfilled
|
||||||
|
|
||||||
it('should return the callback', function() {
|
|
||||||
return this.callback.calledWithExactly().should.equal(true)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -173,160 +125,120 @@ describe('HistoryManager', function() {
|
||||||
last_name: 'Doe',
|
last_name: 'Doe',
|
||||||
email: 'john@example.com'
|
email: 'john@example.com'
|
||||||
}
|
}
|
||||||
this.UserGetter.getUsersByV1Ids = sinon.stub().yields(null, [this.user1])
|
this.UserGetter.promises.getUsersByV1Ids.resolves([this.user1])
|
||||||
return (this.UserGetter.getUsers = sinon
|
this.UserGetter.promises.getUsers.resolves([this.user1, this.user2])
|
||||||
.stub()
|
|
||||||
.yields(null, [this.user1, this.user2]))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with a diff', function() {
|
describe('with a diff', function() {
|
||||||
it('should turn user_ids into user objects', function(done) {
|
it('should turn user_ids into user objects', async function() {
|
||||||
return this.HistoryManager.injectUserDetails(
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
||||||
{
|
diff: [
|
||||||
diff: [
|
{
|
||||||
{
|
i: 'foo',
|
||||||
i: 'foo',
|
meta: {
|
||||||
meta: {
|
users: [this.user_id1]
|
||||||
users: [this.user_id1]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
i: 'bar',
|
|
||||||
meta: {
|
|
||||||
users: [this.user_id2]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
(error, diff) => {
|
i: 'bar',
|
||||||
expect(error).to.be.null
|
meta: {
|
||||||
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
users: [this.user_id2]
|
||||||
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
}
|
||||||
return done()
|
}
|
||||||
}
|
]
|
||||||
)
|
})
|
||||||
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
||||||
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle v1 user ids', function(done) {
|
it('should handle v1 user ids', async function() {
|
||||||
return this.HistoryManager.injectUserDetails(
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
||||||
{
|
diff: [
|
||||||
diff: [
|
{
|
||||||
{
|
i: 'foo',
|
||||||
i: 'foo',
|
meta: {
|
||||||
meta: {
|
users: [5011]
|
||||||
users: [5011]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
i: 'bar',
|
|
||||||
meta: {
|
|
||||||
users: [this.user_id2]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
(error, diff) => {
|
i: 'bar',
|
||||||
expect(error).to.be.null
|
meta: {
|
||||||
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
users: [this.user_id2]
|
||||||
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
}
|
||||||
return done()
|
}
|
||||||
}
|
]
|
||||||
)
|
})
|
||||||
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
||||||
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should leave user objects', function(done) {
|
it('should leave user objects', async function() {
|
||||||
return this.HistoryManager.injectUserDetails(
|
const diff = await this.HistoryManager.promises.injectUserDetails({
|
||||||
{
|
diff: [
|
||||||
diff: [
|
{
|
||||||
{
|
i: 'foo',
|
||||||
i: 'foo',
|
meta: {
|
||||||
meta: {
|
users: [this.user1_view]
|
||||||
users: [this.user1_view]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
i: 'bar',
|
|
||||||
meta: {
|
|
||||||
users: [this.user_id2]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
(error, diff) => {
|
i: 'bar',
|
||||||
expect(error).to.be.null
|
meta: {
|
||||||
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
users: [this.user_id2]
|
||||||
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
}
|
||||||
return done()
|
}
|
||||||
}
|
]
|
||||||
)
|
})
|
||||||
|
expect(diff.diff[0].meta.users).to.deep.equal([this.user1_view])
|
||||||
|
expect(diff.diff[1].meta.users).to.deep.equal([this.user2_view])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with a list of updates', function() {
|
describe('with a list of updates', function() {
|
||||||
it('should turn user_ids into user objects', function(done) {
|
it('should turn user_ids into user objects', async function() {
|
||||||
return this.HistoryManager.injectUserDetails(
|
const updates = await this.HistoryManager.promises.injectUserDetails({
|
||||||
{
|
updates: [
|
||||||
updates: [
|
{
|
||||||
{
|
fromV: 5,
|
||||||
fromV: 5,
|
toV: 8,
|
||||||
toV: 8,
|
meta: {
|
||||||
meta: {
|
users: [this.user_id1]
|
||||||
users: [this.user_id1]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fromV: 4,
|
|
||||||
toV: 5,
|
|
||||||
meta: {
|
|
||||||
users: [this.user_id2]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
(error, updates) => {
|
fromV: 4,
|
||||||
expect(error).to.be.null
|
toV: 5,
|
||||||
expect(updates.updates[0].meta.users).to.deep.equal([
|
meta: {
|
||||||
this.user1_view
|
users: [this.user_id2]
|
||||||
])
|
}
|
||||||
expect(updates.updates[1].meta.users).to.deep.equal([
|
}
|
||||||
this.user2_view
|
]
|
||||||
])
|
})
|
||||||
return done()
|
expect(updates.updates[0].meta.users).to.deep.equal([this.user1_view])
|
||||||
}
|
expect(updates.updates[1].meta.users).to.deep.equal([this.user2_view])
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should leave user objects', function(done) {
|
it('should leave user objects', async function() {
|
||||||
return this.HistoryManager.injectUserDetails(
|
const updates = await this.HistoryManager.promises.injectUserDetails({
|
||||||
{
|
updates: [
|
||||||
updates: [
|
{
|
||||||
{
|
fromV: 5,
|
||||||
fromV: 5,
|
toV: 8,
|
||||||
toV: 8,
|
meta: {
|
||||||
meta: {
|
users: [this.user1_view]
|
||||||
users: [this.user1_view]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fromV: 4,
|
|
||||||
toV: 5,
|
|
||||||
meta: {
|
|
||||||
users: [this.user_id2]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
},
|
{
|
||||||
(error, updates) => {
|
fromV: 4,
|
||||||
expect(error).to.be.null
|
toV: 5,
|
||||||
expect(updates.updates[0].meta.users).to.deep.equal([
|
meta: {
|
||||||
this.user1_view
|
users: [this.user_id2]
|
||||||
])
|
}
|
||||||
expect(updates.updates[1].meta.users).to.deep.equal([
|
}
|
||||||
this.user2_view
|
]
|
||||||
])
|
})
|
||||||
return done()
|
expect(updates.updates[0].meta.users).to.deep.equal([this.user1_view])
|
||||||
}
|
expect(updates.updates[1].meta.users).to.deep.equal([this.user2_view])
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue