mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #2640 from overleaf/em-promisify-project-deleter
Finish promisification of ProjectDeleter GitOrigin-RevId: a426117c9430e2ee66b297b95f67460062a6a809
This commit is contained in:
parent
e7f968d370
commit
864394d4ad
5 changed files with 336 additions and 399 deletions
|
@ -12,15 +12,15 @@
|
||||||
* DS207: Consider shorter variations of null checks
|
* DS207: Consider shorter variations of null checks
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
let DocstoreManager
|
|
||||||
const request = require('request').defaults({ jar: false })
|
const request = require('request').defaults({ jar: false })
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const settings = require('settings-sharelatex')
|
const settings = require('settings-sharelatex')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
|
const { promisifyAll } = require('../../util/promises')
|
||||||
|
|
||||||
const TIMEOUT = 30 * 1000 // request timeout
|
const TIMEOUT = 30 * 1000 // request timeout
|
||||||
|
|
||||||
module.exports = DocstoreManager = {
|
const DocstoreManager = {
|
||||||
deleteDoc(project_id, doc_id, callback) {
|
deleteDoc(project_id, doc_id, callback) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = function(error) {}
|
callback = function(error) {}
|
||||||
|
@ -255,3 +255,11 @@ module.exports = DocstoreManager = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = DocstoreManager
|
||||||
|
module.exports.promises = promisifyAll(DocstoreManager, {
|
||||||
|
multiResult: {
|
||||||
|
getDoc: ['lines', 'rev', 'version', 'ranges'],
|
||||||
|
updateDoc: ['modified', 'rev']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -416,14 +416,6 @@ const EditorController = {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
notifyUsersProjectHasBeenDeletedOrRenamed(project_id, callback) {
|
|
||||||
EditorRealTimeController.emitToRoom(
|
|
||||||
project_id,
|
|
||||||
'projectRenamedOrDeletedByExternalSource'
|
|
||||||
)
|
|
||||||
return callback()
|
|
||||||
},
|
|
||||||
|
|
||||||
updateProjectDescription(project_id, description, callback) {
|
updateProjectDescription(project_id, description, callback) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = function() {}
|
callback = function() {}
|
||||||
|
|
|
@ -1,115 +1,99 @@
|
||||||
const { db, ObjectId } = require('../../infrastructure/mongojs')
|
const { db, ObjectId } = require('../../infrastructure/mongojs')
|
||||||
const { promisify, callbackify } = require('util')
|
const { callbackify } = require('util')
|
||||||
const { Project } = require('../../models/Project')
|
const { Project } = require('../../models/Project')
|
||||||
const { DeletedProject } = require('../../models/DeletedProject')
|
const { DeletedProject } = require('../../models/DeletedProject')
|
||||||
const Errors = require('../Errors/Errors')
|
const Errors = require('../Errors/Errors')
|
||||||
const logger = require('logger-sharelatex')
|
const logger = require('logger-sharelatex')
|
||||||
const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
|
const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
|
||||||
const TagsHandler = require('../Tags/TagsHandler')
|
const TagsHandler = require('../Tags/TagsHandler')
|
||||||
const async = require('async')
|
|
||||||
const ProjectHelper = require('./ProjectHelper')
|
const ProjectHelper = require('./ProjectHelper')
|
||||||
const ProjectDetailsHandler = require('./ProjectDetailsHandler')
|
const ProjectDetailsHandler = require('./ProjectDetailsHandler')
|
||||||
const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
|
const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler')
|
||||||
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
|
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
|
||||||
const DocstoreManager = require('../Docstore/DocstoreManager')
|
const DocstoreManager = require('../Docstore/DocstoreManager')
|
||||||
|
const EditorRealTimeController = require('../Editor/EditorRealTimeController')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
|
const { promiseMapWithLimit } = require('../../util/promises')
|
||||||
|
|
||||||
function logWarningOnError(msg) {
|
const EXPIRE_PROJECTS_AFTER_DAYS = 90
|
||||||
return function(err) {
|
|
||||||
if (err) {
|
module.exports = {
|
||||||
logger.warn({ err }, msg)
|
markAsDeletedByExternalSource: callbackify(markAsDeletedByExternalSource),
|
||||||
}
|
unmarkAsDeletedByExternalSource: callbackify(unmarkAsDeletedByExternalSource),
|
||||||
|
deleteUsersProjects: callbackify(deleteUsersProjects),
|
||||||
|
expireDeletedProjectsAfterDuration: callbackify(
|
||||||
|
expireDeletedProjectsAfterDuration
|
||||||
|
),
|
||||||
|
restoreProject: callbackify(restoreProject),
|
||||||
|
archiveProject: callbackify(archiveProject),
|
||||||
|
unarchiveProject: callbackify(unarchiveProject),
|
||||||
|
trashProject: callbackify(trashProject),
|
||||||
|
untrashProject: callbackify(untrashProject),
|
||||||
|
deleteProject: callbackify(deleteProject),
|
||||||
|
undeleteProject: callbackify(undeleteProject),
|
||||||
|
expireDeletedProject: callbackify(expireDeletedProject),
|
||||||
|
promises: {
|
||||||
|
archiveProject,
|
||||||
|
unarchiveProject,
|
||||||
|
trashProject,
|
||||||
|
untrashProject,
|
||||||
|
deleteProject,
|
||||||
|
undeleteProject,
|
||||||
|
expireDeletedProject,
|
||||||
|
markAsDeletedByExternalSource,
|
||||||
|
unmarkAsDeletedByExternalSource,
|
||||||
|
deleteUsersProjects,
|
||||||
|
expireDeletedProjectsAfterDuration,
|
||||||
|
restoreProject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectDeleter = {
|
async function markAsDeletedByExternalSource(projectId) {
|
||||||
markAsDeletedByExternalSource(projectId, callback) {
|
|
||||||
callback =
|
|
||||||
callback ||
|
|
||||||
logWarningOnError('error marking project as deleted by external source')
|
|
||||||
logger.log(
|
logger.log(
|
||||||
{ project_id: projectId },
|
{ project_id: projectId },
|
||||||
'marking project as deleted by external data source'
|
'marking project as deleted by external data source'
|
||||||
)
|
)
|
||||||
const conditions = { _id: projectId }
|
await Project.update(
|
||||||
const update = { deletedByExternalDataSource: true }
|
{ _id: projectId },
|
||||||
|
{ deletedByExternalDataSource: true }
|
||||||
Project.update(conditions, update, {}, err => {
|
).exec()
|
||||||
if (err) {
|
EditorRealTimeController.emitToRoom(
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
require('../Editor/EditorController').notifyUsersProjectHasBeenDeletedOrRenamed(
|
|
||||||
projectId,
|
projectId,
|
||||||
() => callback() // don't return error, as project has been updated
|
'projectRenamedOrDeletedByExternalSource'
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
},
|
|
||||||
|
|
||||||
unmarkAsDeletedByExternalSource(projectId, callback) {
|
async function unmarkAsDeletedByExternalSource(projectId) {
|
||||||
callback =
|
await Project.update(
|
||||||
callback ||
|
{ _id: projectId },
|
||||||
logWarningOnError('error unmarking project as deleted by external source')
|
{ deletedByExternalDataSource: false }
|
||||||
const conditions = { _id: projectId }
|
).exec()
|
||||||
const update = { deletedByExternalDataSource: false }
|
}
|
||||||
Project.update(conditions, update, {}, callback)
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteUsersProjects(userId, callback) {
|
async function deleteUsersProjects(userId) {
|
||||||
Project.find({ owner_ref: userId }, function(error, projects) {
|
const projects = await Project.find({ owner_ref: userId }).exec()
|
||||||
if (error) {
|
await promiseMapWithLimit(5, projects, project => deleteProject(project._id))
|
||||||
return callback(error)
|
await CollaboratorsHandler.promises.removeUserFromAllProjects(userId)
|
||||||
}
|
}
|
||||||
async.eachLimit(
|
|
||||||
projects,
|
|
||||||
5,
|
|
||||||
(project, cb) => ProjectDeleter.deleteProject(project._id, cb),
|
|
||||||
function(err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
CollaboratorsHandler.removeUserFromAllProjects(userId, callback)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
expireDeletedProjectsAfterDuration(callback) {
|
async function expireDeletedProjectsAfterDuration() {
|
||||||
const DURATION = 90
|
const deletedProjects = await DeletedProject.find({
|
||||||
DeletedProject.find(
|
|
||||||
{
|
|
||||||
'deleterData.deletedAt': {
|
'deleterData.deletedAt': {
|
||||||
$lt: new Date(moment().subtract(DURATION, 'days'))
|
$lt: new Date(moment().subtract(EXPIRE_PROJECTS_AFTER_DAYS, 'days'))
|
||||||
},
|
},
|
||||||
project: {
|
project: { $ne: null }
|
||||||
$ne: null
|
})
|
||||||
}
|
for (const deletedProject of deletedProjects) {
|
||||||
},
|
await expireDeletedProject(deletedProject.deleterData.deletedProjectId)
|
||||||
function(err, deletedProjects) {
|
|
||||||
if (err) {
|
|
||||||
logger.err({ err }, 'Problem with finding deletedProject')
|
|
||||||
return callback(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
async.eachSeries(
|
|
||||||
deletedProjects,
|
|
||||||
function(deletedProject, cb) {
|
|
||||||
ProjectDeleter.expireDeletedProject(
|
|
||||||
deletedProject.deleterData.deletedProjectId,
|
|
||||||
cb
|
|
||||||
)
|
|
||||||
},
|
|
||||||
callback
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
restoreProject(projectId, callback) {
|
|
||||||
Project.update({ _id: projectId }, { $unset: { archived: true } }, callback)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Async methods
|
async function restoreProject(projectId) {
|
||||||
|
await Project.update(
|
||||||
|
{ _id: projectId },
|
||||||
|
{ $unset: { archived: true } }
|
||||||
|
).exec()
|
||||||
|
}
|
||||||
|
|
||||||
async function archiveProject(projectId, userId) {
|
async function archiveProject(projectId, userId) {
|
||||||
try {
|
try {
|
||||||
|
@ -231,17 +215,23 @@ async function deleteProject(projectId, options = {}) {
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const flushProjectToMongoAndDelete = promisify(
|
await DocumentUpdaterHandler.promises.flushProjectToMongoAndDelete(
|
||||||
DocumentUpdaterHandler.flushProjectToMongoAndDelete
|
projectId
|
||||||
)
|
)
|
||||||
await flushProjectToMongoAndDelete(projectId)
|
|
||||||
|
|
||||||
const memberIds = await CollaboratorsGetter.promises.getMemberIds(projectId)
|
const memberIds = await CollaboratorsGetter.promises.getMemberIds(projectId)
|
||||||
|
|
||||||
// fire these jobs in the background
|
// fire these jobs in the background
|
||||||
Array.from(memberIds).forEach(memberId =>
|
for (const memberId of memberIds) {
|
||||||
TagsHandler.removeProjectFromAllTags(memberId, projectId, () => {})
|
TagsHandler.promises
|
||||||
|
.removeProjectFromAllTags(memberId, projectId)
|
||||||
|
.catch(err => {
|
||||||
|
logger.err(
|
||||||
|
{ err, memberId, projectId },
|
||||||
|
'failed to remove project from tags'
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
await Project.remove({ _id: projectId }).exec()
|
await Project.remove({ _id: projectId }).exec()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -309,8 +299,7 @@ async function expireDeletedProject(projectId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const destroyProject = promisify(DocstoreManager.destroyProject)
|
await DocstoreManager.promises.destroyProject(deletedProject.project._id)
|
||||||
await destroyProject(deletedProject.project._id)
|
|
||||||
|
|
||||||
await DeletedProject.update(
|
await DeletedProject.update(
|
||||||
{
|
{
|
||||||
|
@ -328,30 +317,3 @@ async function expireDeletedProject(projectId) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported class
|
|
||||||
|
|
||||||
const promises = {
|
|
||||||
archiveProject: archiveProject,
|
|
||||||
unarchiveProject: unarchiveProject,
|
|
||||||
trashProject: trashProject,
|
|
||||||
untrashProject: untrashProject,
|
|
||||||
deleteProject: deleteProject,
|
|
||||||
undeleteProject: undeleteProject,
|
|
||||||
expireDeletedProject: expireDeletedProject,
|
|
||||||
deleteUsersProjects: promisify(ProjectDeleter.deleteUsersProjects),
|
|
||||||
unmarkAsDeletedByExternalSource: promisify(
|
|
||||||
ProjectDeleter.unmarkAsDeletedByExternalSource
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ProjectDeleter.promises = promises
|
|
||||||
ProjectDeleter.archiveProject = callbackify(archiveProject)
|
|
||||||
ProjectDeleter.unarchiveProject = callbackify(unarchiveProject)
|
|
||||||
ProjectDeleter.trashProject = callbackify(trashProject)
|
|
||||||
ProjectDeleter.untrashProject = callbackify(untrashProject)
|
|
||||||
ProjectDeleter.deleteProject = callbackify(deleteProject)
|
|
||||||
ProjectDeleter.undeleteProject = callbackify(undeleteProject)
|
|
||||||
ProjectDeleter.expireDeletedProject = callbackify(expireDeletedProject)
|
|
||||||
|
|
||||||
module.exports = ProjectDeleter
|
|
||||||
|
|
|
@ -632,23 +632,6 @@ describe('EditorController', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('notifyUsersProjectHasBeenDeletedOrRenamed', function() {
|
|
||||||
it('should emmit a message to all users in a project', function(done) {
|
|
||||||
return this.EditorController.notifyUsersProjectHasBeenDeletedOrRenamed(
|
|
||||||
this.project_id,
|
|
||||||
err => {
|
|
||||||
this.EditorRealTimeController.emitToRoom
|
|
||||||
.calledWith(
|
|
||||||
this.project_id,
|
|
||||||
'projectRenamedOrDeletedByExternalSource'
|
|
||||||
)
|
|
||||||
.should.equal(true)
|
|
||||||
return done()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('updateProjectDescription', function() {
|
describe('updateProjectDescription', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.description = 'new description'
|
this.description = 'new description'
|
||||||
|
|
|
@ -8,46 +8,13 @@ const moment = require('moment')
|
||||||
const { Project } = require('../helpers/models/Project')
|
const { Project } = require('../helpers/models/Project')
|
||||||
const { DeletedProject } = require('../helpers/models/DeletedProject')
|
const { DeletedProject } = require('../helpers/models/DeletedProject')
|
||||||
const { ObjectId } = require('mongoose').Types
|
const { ObjectId } = require('mongoose').Types
|
||||||
|
const Errors = require('../../../../app/src/Features/Errors/Errors')
|
||||||
|
|
||||||
describe('ProjectDeleter', function() {
|
describe('ProjectDeleter', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
tk.freeze(Date.now())
|
tk.freeze(Date.now())
|
||||||
this.project_id = ObjectId('588fffffffffffffffffffff')
|
|
||||||
this.ip = '192.170.18.1'
|
this.ip = '192.170.18.1'
|
||||||
this.project = {
|
this.project = dummyProject()
|
||||||
_id: this.project_id,
|
|
||||||
lastUpdated: new Date(),
|
|
||||||
rootFolder: [],
|
|
||||||
collaberator_refs: [
|
|
||||||
ObjectId('5b895d372f4189011c2f5afc'),
|
|
||||||
ObjectId('5b8d40073ead20011caca726')
|
|
||||||
],
|
|
||||||
readOnly_refs: [
|
|
||||||
ObjectId('5b8d4602b2f786011c4fb244'),
|
|
||||||
ObjectId('5b8d4a57c1cd2b011c39161c')
|
|
||||||
],
|
|
||||||
tokenAccessReadAndWrite_refs: [
|
|
||||||
ObjectId('5b8d5663a26df3035ea0d5a1'),
|
|
||||||
ObjectId('5b8e8676373c14011c2cad3c')
|
|
||||||
],
|
|
||||||
tokenAccessReadOnly_refs: [
|
|
||||||
ObjectId('5b9b801b5dd22c011ba5d9b3'),
|
|
||||||
ObjectId('5bc5adae1cad8d011fd4060a')
|
|
||||||
],
|
|
||||||
owner_ref: ObjectId('588aaaaaaaaaaaaaaaaaaaaa'),
|
|
||||||
tokens: {
|
|
||||||
readOnly: 'wombat',
|
|
||||||
readAndWrite: 'potato'
|
|
||||||
},
|
|
||||||
overleaf: {
|
|
||||||
id: 1234,
|
|
||||||
history: {
|
|
||||||
id: 5678
|
|
||||||
}
|
|
||||||
},
|
|
||||||
name: 'a very scientific analysis of spooky ghosts'
|
|
||||||
}
|
|
||||||
|
|
||||||
this.user = {
|
this.user = {
|
||||||
_id: '588f3ddae8ebc1bac07c9fa4',
|
_id: '588f3ddae8ebc1bac07c9fa4',
|
||||||
first_name: 'bjkdsjfk',
|
first_name: 'bjkdsjfk',
|
||||||
|
@ -94,23 +61,29 @@ describe('ProjectDeleter', function() {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
this.documentUpdaterHandler = {
|
this.DocumentUpdaterHandler = {
|
||||||
flushProjectToMongoAndDelete: sinon.stub().callsArgWith(1)
|
promises: {
|
||||||
|
flushProjectToMongoAndDelete: sinon.stub().resolves()
|
||||||
}
|
}
|
||||||
this.editorController = {
|
}
|
||||||
notifyUsersProjectHasBeenDeletedOrRenamed: sinon.stub().callsArgWith(1)
|
this.EditorRealTimeController = {
|
||||||
|
emitToRoom: sinon.stub()
|
||||||
}
|
}
|
||||||
this.TagsHandler = {
|
this.TagsHandler = {
|
||||||
removeProjectFromAllTags: sinon.stub().callsArgWith(2)
|
promises: {
|
||||||
|
removeProjectFromAllTags: sinon.stub().resolves()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.CollaboratorsHandler = {
|
this.CollaboratorsHandler = {
|
||||||
removeUserFromAllProjects: sinon.stub().yields()
|
promises: {
|
||||||
|
removeUserFromAllProjects: sinon.stub().resolves()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.CollaboratorsGetter = {
|
this.CollaboratorsGetter = {
|
||||||
promises: {
|
promises: {
|
||||||
getMemberIds: sinon
|
getMemberIds: sinon
|
||||||
.stub()
|
.stub()
|
||||||
.withArgs(this.project_id)
|
.withArgs(this.project._id)
|
||||||
.resolves(['member-id-1', 'member-id-2'])
|
.resolves(['member-id-1', 'member-id-2'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +111,9 @@ describe('ProjectDeleter', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.DocstoreManager = {
|
this.DocstoreManager = {
|
||||||
destroyProject: sinon.stub().yields()
|
promises: {
|
||||||
|
destroyProject: sinon.stub().resolves()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ProjectMock = sinon.mock(Project)
|
this.ProjectMock = sinon.mock(Project)
|
||||||
|
@ -146,12 +121,12 @@ describe('ProjectDeleter', function() {
|
||||||
|
|
||||||
this.ProjectDeleter = SandboxedModule.require(modulePath, {
|
this.ProjectDeleter = SandboxedModule.require(modulePath, {
|
||||||
requires: {
|
requires: {
|
||||||
'../Editor/EditorController': this.editorController,
|
'../Editor/EditorRealTimeController': this.EditorRealTimeController,
|
||||||
'../../models/Project': { Project: Project },
|
'../../models/Project': { Project: Project },
|
||||||
'./ProjectHelper': this.ProjectHelper,
|
'./ProjectHelper': this.ProjectHelper,
|
||||||
'../../models/DeletedProject': { DeletedProject: DeletedProject },
|
'../../models/DeletedProject': { DeletedProject: DeletedProject },
|
||||||
'../DocumentUpdater/DocumentUpdaterHandler': this
|
'../DocumentUpdater/DocumentUpdaterHandler': this
|
||||||
.documentUpdaterHandler,
|
.DocumentUpdaterHandler,
|
||||||
'../Tags/TagsHandler': this.TagsHandler,
|
'../Tags/TagsHandler': this.TagsHandler,
|
||||||
'../FileStore/FileStoreHandler': (this.FileStoreHandler = {}),
|
'../FileStore/FileStoreHandler': (this.FileStoreHandler = {}),
|
||||||
'../Collaborators/CollaboratorsHandler': this.CollaboratorsHandler,
|
'../Collaborators/CollaboratorsHandler': this.CollaboratorsHandler,
|
||||||
|
@ -159,7 +134,8 @@ describe('ProjectDeleter', function() {
|
||||||
'../Docstore/DocstoreManager': this.DocstoreManager,
|
'../Docstore/DocstoreManager': this.DocstoreManager,
|
||||||
'./ProjectDetailsHandler': this.ProjectDetailsHandler,
|
'./ProjectDetailsHandler': this.ProjectDetailsHandler,
|
||||||
'../../infrastructure/mongojs': { db: this.db, ObjectId },
|
'../../infrastructure/mongojs': { db: this.db, ObjectId },
|
||||||
'logger-sharelatex': this.logger
|
'logger-sharelatex': this.logger,
|
||||||
|
'../Errors/Errors': Errors
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
console: console
|
console: console
|
||||||
|
@ -177,38 +153,43 @@ describe('ProjectDeleter', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{ _id: this.project_id },
|
{ _id: this.project._id },
|
||||||
{ deletedByExternalDataSource: true }
|
{ deletedByExternalDataSource: true }
|
||||||
)
|
)
|
||||||
.yields()
|
.chain('exec')
|
||||||
|
.resolves()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should update the project with the flag set to true', function(done) {
|
it('should update the project with the flag set to true', async function() {
|
||||||
this.ProjectDeleter.markAsDeletedByExternalSource(this.project_id, () => {
|
await this.ProjectDeleter.promises.markAsDeletedByExternalSource(
|
||||||
|
this.project._id
|
||||||
|
)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
done()
|
})
|
||||||
|
|
||||||
|
it('should tell the editor controler so users are notified', async function() {
|
||||||
|
await this.ProjectDeleter.promises.markAsDeletedByExternalSource(
|
||||||
|
this.project._id
|
||||||
|
)
|
||||||
|
expect(this.EditorRealTimeController.emitToRoom).to.have.been.calledWith(
|
||||||
|
this.project._id,
|
||||||
|
'projectRenamedOrDeletedByExternalSource'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should tell the editor controler so users are notified', function(done) {
|
describe('unmarkAsDeletedByExternalSource', function() {
|
||||||
this.ProjectDeleter.markAsDeletedByExternalSource(this.project_id, () => {
|
beforeEach(async function() {
|
||||||
this.editorController.notifyUsersProjectHasBeenDeletedOrRenamed
|
|
||||||
.calledWith(this.project_id)
|
|
||||||
.should.equal(true)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('unmarkAsDeletedByExternalSource', function(done) {
|
|
||||||
beforeEach(function() {
|
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{ _id: this.project_id },
|
{ _id: this.project._id },
|
||||||
{ deletedByExternalDataSource: false }
|
{ deletedByExternalDataSource: false }
|
||||||
)
|
)
|
||||||
.yields()
|
.chain('exec')
|
||||||
this.ProjectDeleter.unmarkAsDeletedByExternalSource(this.project_id, done)
|
.resolves()
|
||||||
|
await this.ProjectDeleter.promises.unmarkAsDeletedByExternalSource(
|
||||||
|
this.project._id
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove the flag from the project', function() {
|
it('should remove the flag from the project', function() {
|
||||||
|
@ -218,40 +199,48 @@ describe('ProjectDeleter', function() {
|
||||||
|
|
||||||
describe('deleteUsersProjects', function() {
|
describe('deleteUsersProjects', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
this.projects = [dummyProject(), dummyProject()]
|
||||||
this.ProjectMock.expects('find')
|
this.ProjectMock.expects('find')
|
||||||
.withArgs({ owner_ref: this.user._id })
|
.withArgs({ owner_ref: this.user._id })
|
||||||
.yields(null, [{ _id: 'wombat' }, { _id: 'potato' }])
|
.chain('exec')
|
||||||
|
.resolves(this.projects)
|
||||||
this.ProjectDeleter.deleteProject = sinon.stub().yields()
|
for (const project of this.projects) {
|
||||||
|
this.ProjectMock.expects('findOne')
|
||||||
|
.withArgs({ _id: project._id })
|
||||||
|
.chain('exec')
|
||||||
|
.resolves(project)
|
||||||
|
this.ProjectMock.expects('remove')
|
||||||
|
.withArgs({ _id: project._id })
|
||||||
|
.chain('exec')
|
||||||
|
.resolves()
|
||||||
|
this.DeletedProjectMock.expects('update')
|
||||||
|
.withArgs(
|
||||||
|
{ 'deleterData.deletedProjectId': project._id },
|
||||||
|
{
|
||||||
|
project,
|
||||||
|
deleterData: sinon.match.object
|
||||||
|
},
|
||||||
|
{ upsert: true }
|
||||||
|
)
|
||||||
|
.resolves()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find all the projects owned by the user_id', function(done) {
|
it('should delete all projects owned by the user', async function() {
|
||||||
this.ProjectDeleter.deleteUsersProjects(this.user._id, () => {
|
await this.ProjectDeleter.promises.deleteUsersProjects(this.user._id)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
done()
|
this.DeletedProjectMock.verify()
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should call deleteProject once for each project', function(done) {
|
it('should remove any collaboration from this user', async function() {
|
||||||
this.ProjectDeleter.deleteUsersProjects(this.user._id, () => {
|
await this.ProjectDeleter.promises.deleteUsersProjects(this.user._id)
|
||||||
sinon.assert.calledTwice(this.ProjectDeleter.deleteProject)
|
|
||||||
sinon.assert.calledWith(this.ProjectDeleter.deleteProject, 'wombat')
|
|
||||||
sinon.assert.calledWith(this.ProjectDeleter.deleteProject, 'potato')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should remove all the projects the user is a collaborator of', function(done) {
|
|
||||||
this.ProjectDeleter.deleteUsersProjects(this.user._id, () => {
|
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.CollaboratorsHandler.removeUserFromAllProjects,
|
this.CollaboratorsHandler.promises.removeUserFromAllProjects,
|
||||||
this.user._id
|
this.user._id
|
||||||
)
|
)
|
||||||
sinon.assert.calledOnce(
|
sinon.assert.calledOnce(
|
||||||
this.CollaboratorsHandler.removeUserFromAllProjects
|
this.CollaboratorsHandler.promises.removeUserFromAllProjects
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -275,12 +264,12 @@ describe('ProjectDeleter', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ProjectMock.expects('findOne')
|
this.ProjectMock.expects('findOne')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.project)
|
.resolves(this.project)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should save a DeletedProject with additional deleterData', function(done) {
|
it('should save a DeletedProject with additional deleterData', async function() {
|
||||||
this.deleterData.deleterIpAddress = this.ip
|
this.deleterData.deleterIpAddress = this.ip
|
||||||
this.deleterData.deleterId = this.user._id
|
this.deleterData.deleterId = this.user._id
|
||||||
|
|
||||||
|
@ -298,76 +287,61 @@ describe('ProjectDeleter', function() {
|
||||||
)
|
)
|
||||||
.resolves()
|
.resolves()
|
||||||
|
|
||||||
this.ProjectDeleter.deleteProject(
|
await this.ProjectDeleter.promises.deleteProject(this.project._id, {
|
||||||
this.project_id,
|
deleterUser: this.user,
|
||||||
{ deleterUser: this.user, ipAddress: this.ip },
|
ipAddress: this.ip
|
||||||
err => {
|
})
|
||||||
expect(err).not.to.exist
|
|
||||||
this.DeletedProjectMock.verify()
|
this.DeletedProjectMock.verify()
|
||||||
done()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should flushProjectToMongoAndDelete in doc updater', function(done) {
|
it('should flushProjectToMongoAndDelete in doc updater', async function() {
|
||||||
this.ProjectMock.expects('remove')
|
this.ProjectMock.expects('remove')
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves()
|
.resolves()
|
||||||
this.DeletedProjectMock.expects('update').resolves()
|
this.DeletedProjectMock.expects('update').resolves()
|
||||||
|
|
||||||
this.ProjectDeleter.deleteProject(
|
await this.ProjectDeleter.promises.deleteProject(this.project._id, {
|
||||||
this.project_id,
|
deleterUser: this.user,
|
||||||
{ deleterUser: this.user, ipAddress: this.ip },
|
ipAddress: this.ip
|
||||||
() => {
|
})
|
||||||
this.documentUpdaterHandler.flushProjectToMongoAndDelete
|
this.DocumentUpdaterHandler.promises.flushProjectToMongoAndDelete
|
||||||
.calledWith(this.project_id)
|
.calledWith(this.project._id)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
done()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should removeProjectFromAllTags', function(done) {
|
it('should removeProjectFromAllTags', async function() {
|
||||||
this.ProjectMock.expects('remove')
|
this.ProjectMock.expects('remove')
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves()
|
.resolves()
|
||||||
this.DeletedProjectMock.expects('update').resolves()
|
this.DeletedProjectMock.expects('update').resolves()
|
||||||
|
|
||||||
this.ProjectDeleter.deleteProject(this.project_id, () => {
|
await this.ProjectDeleter.promises.deleteProject(this.project._id)
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.TagsHandler.removeProjectFromAllTags,
|
this.TagsHandler.promises.removeProjectFromAllTags,
|
||||||
'member-id-1',
|
'member-id-1',
|
||||||
this.project_id
|
this.project._id
|
||||||
)
|
)
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.TagsHandler.removeProjectFromAllTags,
|
this.TagsHandler.promises.removeProjectFromAllTags,
|
||||||
'member-id-2',
|
'member-id-2',
|
||||||
this.project_id
|
this.project._id
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove the project from Mongo', function(done) {
|
it('should remove the project from Mongo', async function() {
|
||||||
this.ProjectMock.expects('remove')
|
this.ProjectMock.expects('remove')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves()
|
.resolves()
|
||||||
this.DeletedProjectMock.expects('update').resolves()
|
this.DeletedProjectMock.expects('update').resolves()
|
||||||
|
|
||||||
this.ProjectDeleter.deleteProject(this.project_id, () => {
|
await this.ProjectDeleter.promises.deleteProject(this.project._id)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('expireDeletedProjectsAfterDuration', function() {
|
describe('expireDeletedProjectsAfterDuration', function() {
|
||||||
beforeEach(function(done) {
|
beforeEach(async function() {
|
||||||
this.ProjectDeleter.expireDeletedProject = sinon
|
|
||||||
.stub()
|
|
||||||
.callsArgWith(1, null)
|
|
||||||
|
|
||||||
this.DeletedProjectMock.expects('find')
|
this.DeletedProjectMock.expects('find')
|
||||||
.withArgs({
|
.withArgs({
|
||||||
'deleterData.deletedAt': {
|
'deleterData.deletedAt': {
|
||||||
|
@ -377,25 +351,42 @@ describe('ProjectDeleter', function() {
|
||||||
$ne: null
|
$ne: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.yields(null, this.deletedProjects)
|
.chain('exec')
|
||||||
|
.resolves(this.deletedProjects)
|
||||||
|
|
||||||
this.ProjectDeleter.expireDeletedProjectsAfterDuration(done)
|
for (const deletedProject of this.deletedProjects) {
|
||||||
|
this.DeletedProjectMock.expects('findOne')
|
||||||
|
.withArgs({
|
||||||
|
'deleterData.deletedProjectId': deletedProject.project._id
|
||||||
})
|
})
|
||||||
|
.chain('exec')
|
||||||
it('should call find with a date 90 days earlier than today', function() {
|
.resolves(deletedProject)
|
||||||
this.DeletedProjectMock.verify()
|
this.DeletedProjectMock.expects('update')
|
||||||
})
|
.withArgs(
|
||||||
|
{
|
||||||
it('should call expireDeletedProject', function(done) {
|
_id: deletedProject._id
|
||||||
expect(this.ProjectDeleter.expireDeletedProject).to.have.been.calledWith(
|
},
|
||||||
this.deletedProjects[0].deleterData.deletedProjectId
|
{
|
||||||
|
$set: {
|
||||||
|
'deleterData.deleterIpAddress': null,
|
||||||
|
project: null
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
done()
|
.chain('exec')
|
||||||
|
.resolves()
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.ProjectDeleter.promises.expireDeletedProjectsAfterDuration()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should expire projects older than 90 days', function() {
|
||||||
|
this.DeletedProjectMock.verify()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('expireDeletedProject', function() {
|
describe('expireDeletedProject', function() {
|
||||||
beforeEach(function(done) {
|
beforeEach(async function() {
|
||||||
this.DeletedProjectMock.expects('update')
|
this.DeletedProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{
|
{
|
||||||
|
@ -418,9 +409,8 @@ describe('ProjectDeleter', function() {
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.deletedProjects[0])
|
.resolves(this.deletedProjects[0])
|
||||||
|
|
||||||
this.ProjectDeleter.expireDeletedProject(
|
await this.ProjectDeleter.promises.expireDeletedProject(
|
||||||
this.deletedProjects[0].project._id,
|
this.deletedProjects[0].project._id
|
||||||
done
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -429,9 +419,9 @@ describe('ProjectDeleter', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should destroy the docs in docstore', function() {
|
it('should destroy the docs in docstore', function() {
|
||||||
expect(this.DocstoreManager.destroyProject).to.have.been.calledWith(
|
expect(
|
||||||
this.deletedProjects[0].project._id
|
this.DocstoreManager.promises.destroyProject
|
||||||
)
|
).to.have.been.calledWith(this.deletedProjects[0].project._id)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -441,13 +431,13 @@ describe('ProjectDeleter', function() {
|
||||||
this.ProjectHelper.calculateArchivedArray.returns(archived)
|
this.ProjectHelper.calculateArchivedArray.returns(archived)
|
||||||
|
|
||||||
this.ProjectMock.expects('findOne')
|
this.ProjectMock.expects('findOne')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.project)
|
.resolves(this.project)
|
||||||
|
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{ _id: this.project_id },
|
{ _id: this.project._id },
|
||||||
{
|
{
|
||||||
$set: { archived: archived },
|
$set: { archived: archived },
|
||||||
$pull: { trashed: ObjectId(this.user._id) }
|
$pull: { trashed: ObjectId(this.user._id) }
|
||||||
|
@ -458,7 +448,7 @@ describe('ProjectDeleter', function() {
|
||||||
|
|
||||||
it('should update the project', async function() {
|
it('should update the project', async function() {
|
||||||
await this.ProjectDeleter.promises.archiveProject(
|
await this.ProjectDeleter.promises.archiveProject(
|
||||||
this.project_id,
|
this.project._id,
|
||||||
this.user._id
|
this.user._id
|
||||||
)
|
)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
|
@ -471,18 +461,18 @@ describe('ProjectDeleter', function() {
|
||||||
this.ProjectHelper.calculateArchivedArray.returns(archived)
|
this.ProjectHelper.calculateArchivedArray.returns(archived)
|
||||||
|
|
||||||
this.ProjectMock.expects('findOne')
|
this.ProjectMock.expects('findOne')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.project)
|
.resolves(this.project)
|
||||||
|
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs({ _id: this.project_id }, { $set: { archived: archived } })
|
.withArgs({ _id: this.project._id }, { $set: { archived: archived } })
|
||||||
.resolves()
|
.resolves()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should update the project', async function() {
|
it('should update the project', async function() {
|
||||||
await this.ProjectDeleter.promises.unarchiveProject(
|
await this.ProjectDeleter.promises.unarchiveProject(
|
||||||
this.project_id,
|
this.project._id,
|
||||||
this.user._id
|
this.user._id
|
||||||
)
|
)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
|
@ -492,13 +482,13 @@ describe('ProjectDeleter', function() {
|
||||||
describe('trashProject', function() {
|
describe('trashProject', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.ProjectMock.expects('findOne')
|
this.ProjectMock.expects('findOne')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.project)
|
.resolves(this.project)
|
||||||
|
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{ _id: this.project_id },
|
{ _id: this.project._id },
|
||||||
{
|
{
|
||||||
$addToSet: { trashed: ObjectId(this.user._id) },
|
$addToSet: { trashed: ObjectId(this.user._id) },
|
||||||
$pull: { archived: ObjectId(this.user._id) }
|
$pull: { archived: ObjectId(this.user._id) }
|
||||||
|
@ -509,7 +499,7 @@ describe('ProjectDeleter', function() {
|
||||||
|
|
||||||
it('should update the project', async function() {
|
it('should update the project', async function() {
|
||||||
await this.ProjectDeleter.promises.trashProject(
|
await this.ProjectDeleter.promises.trashProject(
|
||||||
this.project_id,
|
this.project._id,
|
||||||
this.user._id
|
this.user._id
|
||||||
)
|
)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
|
@ -519,13 +509,13 @@ describe('ProjectDeleter', function() {
|
||||||
describe('untrashProject', function() {
|
describe('untrashProject', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.ProjectMock.expects('findOne')
|
this.ProjectMock.expects('findOne')
|
||||||
.withArgs({ _id: this.project_id })
|
.withArgs({ _id: this.project._id })
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves(this.project)
|
.resolves(this.project)
|
||||||
|
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{ _id: this.project_id },
|
{ _id: this.project._id },
|
||||||
{ $pull: { trashed: ObjectId(this.user._id) } }
|
{ $pull: { trashed: ObjectId(this.user._id) } }
|
||||||
)
|
)
|
||||||
.resolves()
|
.resolves()
|
||||||
|
@ -533,7 +523,7 @@ describe('ProjectDeleter', function() {
|
||||||
|
|
||||||
it('should update the project', async function() {
|
it('should update the project', async function() {
|
||||||
await this.ProjectDeleter.promises.untrashProject(
|
await this.ProjectDeleter.promises.untrashProject(
|
||||||
this.project_id,
|
this.project._id,
|
||||||
this.user._id
|
this.user._id
|
||||||
)
|
)
|
||||||
this.ProjectMock.verify()
|
this.ProjectMock.verify()
|
||||||
|
@ -545,20 +535,18 @@ describe('ProjectDeleter', function() {
|
||||||
this.ProjectMock.expects('update')
|
this.ProjectMock.expects('update')
|
||||||
.withArgs(
|
.withArgs(
|
||||||
{
|
{
|
||||||
_id: this.project_id
|
_id: this.project._id
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$unset: { archived: true }
|
$unset: { archived: true }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.yields()
|
.chain('exec')
|
||||||
|
.resolves()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should unset the archive attribute', function(done) {
|
it('should unset the archive attribute', async function() {
|
||||||
this.ProjectDeleter.restoreProject(this.project_id, () => {
|
await this.ProjectDeleter.promises.restoreProject(this.project._id)
|
||||||
this.ProjectMock.verify()
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -597,26 +585,20 @@ describe('ProjectDeleter', function() {
|
||||||
.resolves()
|
.resolves()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return not found if the project does not exist', function(done) {
|
it('should return not found if the project does not exist', async function() {
|
||||||
this.ProjectDeleter.undeleteProject('wombat', err => {
|
await expect(
|
||||||
expect(err).to.exist
|
this.ProjectDeleter.promises.undeleteProject('wombat')
|
||||||
expect(err.name).to.equal('NotFoundError')
|
).to.be.rejectedWith(Errors.NotFoundError, 'project_not_found')
|
||||||
expect(err.message).to.equal('project_not_found')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return not found if the project has been expired', function(done) {
|
it('should return not found if the project has been expired', async function() {
|
||||||
this.ProjectDeleter.undeleteProject('purgedProject', err => {
|
await expect(
|
||||||
expect(err.name).to.equal('NotFoundError')
|
this.ProjectDeleter.promises.undeleteProject('purgedProject')
|
||||||
expect(err.message).to.equal('project_too_old_to_restore')
|
).to.be.rejectedWith(Errors.NotFoundError, 'project_too_old_to_restore')
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should insert the project into the collection', function(done) {
|
it('should insert the project into the collection', async function() {
|
||||||
this.ProjectDeleter.undeleteProject(this.project._id, err => {
|
await this.ProjectDeleter.promises.undeleteProject(this.project._id)
|
||||||
expect(err).not.to.exist
|
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.db.projects.insert,
|
this.db.projects.insert,
|
||||||
sinon.match({
|
sinon.match({
|
||||||
|
@ -624,46 +606,35 @@ describe('ProjectDeleter', function() {
|
||||||
name: this.project.name
|
name: this.project.name
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should clear the archive bit', function(done) {
|
it('should clear the archive bit', async function() {
|
||||||
this.project.archived = true
|
this.project.archived = true
|
||||||
this.ProjectDeleter.undeleteProject(this.project._id, err => {
|
await this.ProjectDeleter.promises.undeleteProject(this.project._id)
|
||||||
expect(err).not.to.exist
|
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.db.projects.insert,
|
this.db.projects.insert,
|
||||||
sinon.match({ archived: undefined })
|
sinon.match({ archived: undefined })
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should generate a unique name for the project', function(done) {
|
it('should generate a unique name for the project', async function() {
|
||||||
this.ProjectDeleter.undeleteProject(this.project._id, err => {
|
await this.ProjectDeleter.promises.undeleteProject(this.project._id)
|
||||||
expect(err).not.to.exist
|
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.ProjectDetailsHandler.promises.generateUniqueName,
|
this.ProjectDetailsHandler.promises.generateUniqueName,
|
||||||
this.project.owner_ref
|
this.project.owner_ref
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should add a suffix to the project name', function(done) {
|
it('should add a suffix to the project name', async function() {
|
||||||
this.ProjectDeleter.undeleteProject(this.project._id, err => {
|
await this.ProjectDeleter.promises.undeleteProject(this.project._id)
|
||||||
expect(err).not.to.exist
|
|
||||||
sinon.assert.calledWith(
|
sinon.assert.calledWith(
|
||||||
this.ProjectDetailsHandler.promises.generateUniqueName,
|
this.ProjectDetailsHandler.promises.generateUniqueName,
|
||||||
this.project.owner_ref,
|
this.project.owner_ref,
|
||||||
this.project.name + ' (Restored)'
|
this.project.name + ' (Restored)'
|
||||||
)
|
)
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove the DeletedProject', function(done) {
|
it('should remove the DeletedProject', async function() {
|
||||||
// need to change the mock just to include the methods we want
|
// need to change the mock just to include the methods we want
|
||||||
this.DeletedProjectMock.restore()
|
this.DeletedProjectMock.restore()
|
||||||
this.DeletedProjectMock = sinon.mock(DeletedProject)
|
this.DeletedProjectMock = sinon.mock(DeletedProject)
|
||||||
|
@ -676,11 +647,32 @@ describe('ProjectDeleter', function() {
|
||||||
.chain('exec')
|
.chain('exec')
|
||||||
.resolves()
|
.resolves()
|
||||||
|
|
||||||
this.ProjectDeleter.undeleteProject(this.project._id, err => {
|
await this.ProjectDeleter.promises.undeleteProject(this.project._id)
|
||||||
expect(err).not.to.exist
|
|
||||||
this.DeletedProjectMock.verify()
|
this.DeletedProjectMock.verify()
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function dummyProject() {
|
||||||
|
return {
|
||||||
|
_id: new ObjectId(),
|
||||||
|
lastUpdated: new Date(),
|
||||||
|
rootFolder: [],
|
||||||
|
collaberator_refs: [new ObjectId(), new ObjectId()],
|
||||||
|
readOnly_refs: [new ObjectId(), new ObjectId()],
|
||||||
|
tokenAccessReadAndWrite_refs: [new ObjectId(), new ObjectId()],
|
||||||
|
tokenAccessReadOnly_refs: [new ObjectId(), new ObjectId()],
|
||||||
|
owner_ref: new ObjectId(),
|
||||||
|
tokens: {
|
||||||
|
readOnly: 'wombat',
|
||||||
|
readAndWrite: 'potato'
|
||||||
|
},
|
||||||
|
overleaf: {
|
||||||
|
id: 1234,
|
||||||
|
history: {
|
||||||
|
id: 5678
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name: 'a very scientific analysis of spooky ghosts'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue