mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 22:23:42 +01:00
Merge pull request #9658 from overleaf/em-dropbox-folder-sync
Sync folder creation from Dropbox to Overleaf GitOrigin-RevId: a2749ab8d9db7dd312818b46d6e72f1dbaaaff2e
This commit is contained in:
@@ -653,5 +653,9 @@ const EditorController = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorController.promises = promisifyAll(EditorController)
|
EditorController.promises = promisifyAll(EditorController, {
|
||||||
|
multiResult: {
|
||||||
|
mkdirp: ['newFolders', 'lastFolder'],
|
||||||
|
},
|
||||||
|
})
|
||||||
module.exports = EditorController
|
module.exports = EditorController
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ module.exports = {
|
|||||||
mkdirp: callbackifyMultiResult(wrapWithLock(mkdirp), [
|
mkdirp: callbackifyMultiResult(wrapWithLock(mkdirp), [
|
||||||
'newFolders',
|
'newFolders',
|
||||||
'folder',
|
'folder',
|
||||||
|
'parentFolder',
|
||||||
]),
|
]),
|
||||||
moveEntity: callbackifyMultiResult(wrapWithLock(moveEntity), [
|
moveEntity: callbackifyMultiResult(wrapWithLock(moveEntity), [
|
||||||
'project',
|
'project',
|
||||||
@@ -279,13 +280,14 @@ async function mkdirp(projectId, path, options = {}) {
|
|||||||
for (const folderName of folders) {
|
for (const folderName of folders) {
|
||||||
builtUpPath += `/${folderName}`
|
builtUpPath += `/${folderName}`
|
||||||
try {
|
try {
|
||||||
const { element: foundFolder } =
|
const { element: foundFolder, folder: parentFolder } =
|
||||||
await ProjectLocator.promises.findElementByPath({
|
await ProjectLocator.promises.findElementByPath({
|
||||||
project,
|
project,
|
||||||
path: builtUpPath,
|
path: builtUpPath,
|
||||||
exactCaseMatch: options.exactCaseMatch,
|
exactCaseMatch: options.exactCaseMatch,
|
||||||
})
|
})
|
||||||
lastFolder = foundFolder
|
lastFolder = foundFolder
|
||||||
|
lastFolder.parentFolder_id = parentFolder._id
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Folder couldn't be found. Create it.
|
// Folder couldn't be found. Create it.
|
||||||
const parentFolderId = lastFolder && lastFolder._id
|
const parentFolderId = lastFolder && lastFolder._id
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ function _findElementByPathWithProject(
|
|||||||
function getEntity(folder, entityName, cb) {
|
function getEntity(folder, entityName, cb) {
|
||||||
let result, type
|
let result, type
|
||||||
if (entityName == null) {
|
if (entityName == null) {
|
||||||
return cb(null, folder, 'folder')
|
return cb(null, folder, 'folder', null)
|
||||||
}
|
}
|
||||||
for (const file of iterablePaths(folder, 'fileRefs')) {
|
for (const file of iterablePaths(folder, 'fileRefs')) {
|
||||||
if (matchFn(file != null ? file.name : undefined, entityName)) {
|
if (matchFn(file != null ? file.name : undefined, entityName)) {
|
||||||
@@ -227,7 +227,7 @@ function _findElementByPathWithProject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
cb(null, result, type)
|
cb(null, result, type, folder)
|
||||||
} else {
|
} else {
|
||||||
cb(
|
cb(
|
||||||
new Error(
|
new Error(
|
||||||
@@ -241,7 +241,7 @@ function _findElementByPathWithProject(
|
|||||||
return callback(new Error('Tried to find an element for a null project'))
|
return callback(new Error('Tried to find an element for a null project'))
|
||||||
}
|
}
|
||||||
if (needlePath === '' || needlePath === '/') {
|
if (needlePath === '' || needlePath === '/') {
|
||||||
return callback(null, project.rootFolder[0], 'folder')
|
return callback(null, project.rootFolder[0], 'folder', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needlePath.indexOf('/') === 0) {
|
if (needlePath.indexOf('/') === 0) {
|
||||||
@@ -317,6 +317,7 @@ module.exports = {
|
|||||||
findElementByPath: promisifyMultiResult(findElementByPath, [
|
findElementByPath: promisifyMultiResult(findElementByPath, [
|
||||||
'element',
|
'element',
|
||||||
'type',
|
'type',
|
||||||
|
'folder',
|
||||||
]),
|
]),
|
||||||
findRootDoc: promisifyMultiResult(findRootDoc, [
|
findRootDoc: promisifyMultiResult(findRootDoc, [
|
||||||
'element',
|
'element',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const Path = require('path')
|
|||||||
const metrics = require('@overleaf/metrics')
|
const metrics = require('@overleaf/metrics')
|
||||||
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
|
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
|
||||||
const SessionManager = require('../Authentication/SessionManager')
|
const SessionManager = require('../Authentication/SessionManager')
|
||||||
|
const HttpErrorHandler = require('../Errors/HttpErrorHandler')
|
||||||
const TpdsQueueManager = require('./TpdsQueueManager')
|
const TpdsQueueManager = require('./TpdsQueueManager')
|
||||||
|
|
||||||
// mergeUpdate and deleteUpdate are used by Dropbox, where the project is only
|
// mergeUpdate and deleteUpdate are used by Dropbox, where the project is only
|
||||||
@@ -80,6 +81,32 @@ async function deleteUpdate(req, res) {
|
|||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update endpoint that accepts update details as JSON
|
||||||
|
*/
|
||||||
|
async function updateFolder(req, res) {
|
||||||
|
const userId = req.body.userId
|
||||||
|
const { projectName, filePath } = splitPath(req.body.path)
|
||||||
|
const metadata = await TpdsUpdateHandler.promises.createFolder(
|
||||||
|
userId,
|
||||||
|
projectName,
|
||||||
|
filePath
|
||||||
|
)
|
||||||
|
if (metadata == null) {
|
||||||
|
return HttpErrorHandler.conflict(req, res, 'Could not create folder', {
|
||||||
|
userId,
|
||||||
|
projectName,
|
||||||
|
filePath,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
entityId: metadata.folderId.toString(),
|
||||||
|
projectId: metadata.projectId.toString(),
|
||||||
|
path: metadata.path,
|
||||||
|
folderId: metadata.parentFolderId.toString(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// updateProjectContents and deleteProjectContents are used by GitHub. The
|
// updateProjectContents and deleteProjectContents are used by GitHub. The
|
||||||
// project_id is known so we can skip right ahead to creating/updating/deleting
|
// project_id is known so we can skip right ahead to creating/updating/deleting
|
||||||
// the file. These methods will not ignore noisy files like .DS_Store,
|
// the file. These methods will not ignore noisy files like .DS_Store,
|
||||||
@@ -118,10 +145,13 @@ async function getQueues(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseParams(req) {
|
function parseParams(req) {
|
||||||
let filePath, projectName
|
|
||||||
let path = req.params[0]
|
|
||||||
const userId = req.params.user_id
|
const userId = req.params.user_id
|
||||||
|
const { projectName, filePath } = splitPath(req.params[0])
|
||||||
|
return { filePath, userId, projectName }
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitPath(path) {
|
||||||
|
let filePath, projectName
|
||||||
path = Path.join('/', path)
|
path = Path.join('/', path)
|
||||||
if (path.substring(1).indexOf('/') === -1) {
|
if (path.substring(1).indexOf('/') === -1) {
|
||||||
filePath = '/'
|
filePath = '/'
|
||||||
@@ -132,12 +162,13 @@ function parseParams(req) {
|
|||||||
projectName = projectName.replace('/', '')
|
projectName = projectName.replace('/', '')
|
||||||
}
|
}
|
||||||
|
|
||||||
return { filePath, userId, projectName }
|
return { projectName, filePath }
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mergeUpdate: expressify(mergeUpdate),
|
mergeUpdate: expressify(mergeUpdate),
|
||||||
deleteUpdate: expressify(deleteUpdate),
|
deleteUpdate: expressify(deleteUpdate),
|
||||||
|
updateFolder: expressify(updateFolder),
|
||||||
updateProjectContents: expressify(updateProjectContents),
|
updateProjectContents: expressify(updateProjectContents),
|
||||||
deleteProjectContents: expressify(deleteProjectContents),
|
deleteProjectContents: expressify(deleteProjectContents),
|
||||||
getQueues: expressify(getQueues),
|
getQueues: expressify(getQueues),
|
||||||
|
|||||||
@@ -144,11 +144,39 @@ async function handleDuplicateProjects(userId, projectName) {
|
|||||||
.create(projectName)
|
.create(projectName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createFolder(userId, projectName, path) {
|
||||||
|
const project = await getOrCreateProject(userId, projectName)
|
||||||
|
if (project == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectIsOnCooldown =
|
||||||
|
await CooldownManager.promises.isProjectOnCooldown(project._id)
|
||||||
|
if (projectIsOnCooldown) {
|
||||||
|
throw new Errors.TooManyRequestsError('project on cooldown')
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldIgnore = await FileTypeManager.promises.shouldIgnore(path)
|
||||||
|
if (shouldIgnore) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const folder = await UpdateMerger.promises.createFolder(project._id, path)
|
||||||
|
return {
|
||||||
|
folderId: folder._id,
|
||||||
|
parentFolderId: folder.parentFolder_id,
|
||||||
|
projectId: project._id,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
newUpdate: callbackify(newUpdate),
|
newUpdate: callbackify(newUpdate),
|
||||||
deleteUpdate: callbackify(deleteUpdate),
|
deleteUpdate: callbackify(deleteUpdate),
|
||||||
|
createFolder: callbackify(createFolder),
|
||||||
promises: {
|
promises: {
|
||||||
newUpdate,
|
newUpdate,
|
||||||
deleteUpdate,
|
deleteUpdate,
|
||||||
|
createFolder,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,13 +157,23 @@ async function _readFileIntoTextArray(path) {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createFolder(projectId, path) {
|
||||||
|
const { lastFolder: folder } = await EditorController.promises.mkdirp(
|
||||||
|
projectId,
|
||||||
|
path
|
||||||
|
)
|
||||||
|
return folder
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mergeUpdate: callbackify(mergeUpdate),
|
mergeUpdate: callbackify(mergeUpdate),
|
||||||
_mergeUpdate: callbackify(_mergeUpdate),
|
_mergeUpdate: callbackify(_mergeUpdate),
|
||||||
deleteUpdate: callbackify(deleteUpdate),
|
deleteUpdate: callbackify(deleteUpdate),
|
||||||
|
createFolder: callbackify(createFolder),
|
||||||
promises: {
|
promises: {
|
||||||
mergeUpdate,
|
mergeUpdate,
|
||||||
_mergeUpdate, // called by GitBridgeHandler
|
_mergeUpdate, // called by GitBridgeHandler
|
||||||
deleteUpdate,
|
deleteUpdate,
|
||||||
|
createFolder,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -908,6 +908,11 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
|
|||||||
DocumentController.setDocument
|
DocumentController.setDocument
|
||||||
)
|
)
|
||||||
|
|
||||||
|
privateApiRouter.post(
|
||||||
|
'/tpds/folder-update',
|
||||||
|
AuthenticationController.requirePrivateApiAuth(),
|
||||||
|
TpdsController.updateFolder
|
||||||
|
)
|
||||||
privateApiRouter.post(
|
privateApiRouter.post(
|
||||||
'/user/:user_id/update/*',
|
'/user/:user_id/update/*',
|
||||||
AuthenticationController.requirePrivateApiAuth(),
|
AuthenticationController.requirePrivateApiAuth(),
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
|
|||||||
path: '/',
|
path: '/',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.resolves({ element: this.rootFolder, type: 'folder' })
|
.resolves({ element: this.rootFolder, type: 'folder', folder: null })
|
||||||
this.ProjectLocator.promises.findElementByPath
|
this.ProjectLocator.promises.findElementByPath
|
||||||
.withArgs(
|
.withArgs(
|
||||||
sinon.match({
|
sinon.match({
|
||||||
@@ -152,7 +152,11 @@ describe('ProjectEntityMongoUpdateHandler', function () {
|
|||||||
path: '/test-folder',
|
path: '/test-folder',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.resolves({ element: this.folder, type: 'folder' })
|
.resolves({
|
||||||
|
element: this.folder,
|
||||||
|
type: 'folder',
|
||||||
|
folder: this.rootFolder,
|
||||||
|
})
|
||||||
this.ProjectLocator.promises.findElementByPath
|
this.ProjectLocator.promises.findElementByPath
|
||||||
.withArgs(
|
.withArgs(
|
||||||
sinon.match({
|
sinon.match({
|
||||||
@@ -160,7 +164,11 @@ describe('ProjectEntityMongoUpdateHandler', function () {
|
|||||||
path: '/test-folder/test-subfolder',
|
path: '/test-folder/test-subfolder',
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.resolves({ element: this.subfolder, type: 'folder' })
|
.resolves({
|
||||||
|
element: this.subfolder,
|
||||||
|
type: 'folder',
|
||||||
|
folder: this.folder,
|
||||||
|
})
|
||||||
|
|
||||||
this.ProjectGetter = {
|
this.ProjectGetter = {
|
||||||
promises: {
|
promises: {
|
||||||
@@ -437,9 +445,7 @@ describe('ProjectEntityMongoUpdateHandler', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should report the parent folder', function () {
|
it('should report the parent folder', function () {
|
||||||
expect(this.result.folder.parentFolder_id).not.equal(
|
expect(this.result.folder.parentFolder_id).to.equal(this.rootFolder._id)
|
||||||
this.rootFolder._id
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not return new folders', function () {
|
it('should not return new folders', function () {
|
||||||
|
|||||||
@@ -308,12 +308,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${doc1.name}`
|
const path = `${doc1.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(doc1)
|
element.should.deep.equal(doc1)
|
||||||
expect(type).to.equal('doc')
|
expect(type).to.equal('doc')
|
||||||
|
expect(folder).to.equal(rootFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -323,12 +324,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `/${doc1.name}`
|
const path = `/${doc1.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(doc1)
|
element.should.deep.equal(doc1)
|
||||||
expect(type).to.equal('doc')
|
expect(type).to.equal('doc')
|
||||||
|
expect(folder).to.equal(rootFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -338,12 +340,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${subFolder.name}/${secondSubFolder.name}/${subSubDoc.name}`
|
const path = `${subFolder.name}/${secondSubFolder.name}/${subSubDoc.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(subSubDoc)
|
element.should.deep.equal(subSubDoc)
|
||||||
expect(type).to.equal('doc')
|
expect(type).to.equal('doc')
|
||||||
|
expect(folder).to.equal(secondSubFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -353,12 +356,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${file1.name}`
|
const path = `${file1.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(file1)
|
element.should.deep.equal(file1)
|
||||||
expect(type).to.equal('file')
|
expect(type).to.equal('file')
|
||||||
|
expect(folder).to.equal(rootFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -368,12 +372,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${subFolder.name}/${secondSubFolder.name}/${subSubFile.name}`
|
const path = `${subFolder.name}/${secondSubFolder.name}/${subSubFile.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(subSubFile)
|
element.should.deep.equal(subSubFile)
|
||||||
expect(type).to.equal('file')
|
expect(type).to.equal('file')
|
||||||
|
expect(folder).to.equal(secondSubFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -383,12 +388,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${subFolder.name.toUpperCase()}/${secondSubFolder.name.toUpperCase()}/${subSubFile.name.toUpperCase()}`
|
const path = `${subFolder.name.toUpperCase()}/${secondSubFolder.name.toUpperCase()}/${subSubFile.name.toUpperCase()}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(subSubFile)
|
element.should.deep.equal(subSubFile)
|
||||||
expect(type).to.equal('file')
|
expect(type).to.equal('file')
|
||||||
|
expect(folder).to.equal(secondSubFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -398,12 +404,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = `${subFolder.name}/${secondSubFolder.name}`
|
const path = `${subFolder.name}/${secondSubFolder.name}`
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(secondSubFolder)
|
element.should.deep.equal(secondSubFolder)
|
||||||
expect(type).to.equal('folder')
|
expect(type).to.equal('folder')
|
||||||
|
expect(folder).to.equal(subFolder)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -413,12 +420,13 @@ describe('ProjectLocator', function () {
|
|||||||
const path = '/'
|
const path = '/'
|
||||||
this.locator.findElementByPath(
|
this.locator.findElementByPath(
|
||||||
{ project, path },
|
{ project, path },
|
||||||
(err, element, type) => {
|
(err, element, type, folder) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
return done(err)
|
return done(err)
|
||||||
}
|
}
|
||||||
element.should.deep.equal(rootFolder)
|
element.should.deep.equal(rootFolder)
|
||||||
expect(type).to.equal('folder')
|
expect(type).to.equal('folder')
|
||||||
|
expect(folder).to.equal(null)
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ describe('TpdsController', function () {
|
|||||||
promises: {
|
promises: {
|
||||||
newUpdate: sinon.stub().resolves(this.metadata),
|
newUpdate: sinon.stub().resolves(this.metadata),
|
||||||
deleteUpdate: sinon.stub().resolves(),
|
deleteUpdate: sinon.stub().resolves(),
|
||||||
|
createFolder: sinon.stub().resolves(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
this.UpdateMerger = {
|
this.UpdateMerger = {
|
||||||
@@ -38,6 +39,9 @@ describe('TpdsController', function () {
|
|||||||
getQueues: sinon.stub().resolves('queues'),
|
getQueues: sinon.stub().resolves('queues'),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
this.HttpErrorHandler = {
|
||||||
|
conflict: sinon.stub(),
|
||||||
|
}
|
||||||
|
|
||||||
this.TpdsController = SandboxedModule.require(MODULE_PATH, {
|
this.TpdsController = SandboxedModule.require(MODULE_PATH, {
|
||||||
requires: {
|
requires: {
|
||||||
@@ -45,6 +49,7 @@ describe('TpdsController', function () {
|
|||||||
'./UpdateMerger': this.UpdateMerger,
|
'./UpdateMerger': this.UpdateMerger,
|
||||||
'../Notifications/NotificationsBuilder': this.NotificationsBuilder,
|
'../Notifications/NotificationsBuilder': this.NotificationsBuilder,
|
||||||
'../Authentication/SessionManager': this.SessionManager,
|
'../Authentication/SessionManager': this.SessionManager,
|
||||||
|
'../Errors/HttpErrorHandler': this.HttpErrorHandler,
|
||||||
'./TpdsQueueManager': this.TpdsQueueManager,
|
'./TpdsQueueManager': this.TpdsQueueManager,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -166,6 +171,47 @@ describe('TpdsController', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('updateFolder', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
this.req = {
|
||||||
|
body: { userId: this.user_id, path: '/abc/def/ghi.txt' },
|
||||||
|
}
|
||||||
|
this.res = {
|
||||||
|
json: sinon.stub(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("creates a folder if it doesn't exist", function (done) {
|
||||||
|
const metadata = {
|
||||||
|
folderId: ObjectId(),
|
||||||
|
projectId: ObjectId(),
|
||||||
|
path: '/def/ghi.txt',
|
||||||
|
parentFolderId: ObjectId(),
|
||||||
|
}
|
||||||
|
this.TpdsUpdateHandler.promises.createFolder.resolves(metadata)
|
||||||
|
this.res.json.callsFake(body => {
|
||||||
|
expect(body).to.deep.equal({
|
||||||
|
entityId: metadata.folderId.toString(),
|
||||||
|
projectId: metadata.projectId.toString(),
|
||||||
|
path: metadata.path,
|
||||||
|
folderId: metadata.parentFolderId.toString(),
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
this.TpdsController.updateFolder(this.req, this.res)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a 409 if the folder couldn't be created", function (done) {
|
||||||
|
this.TpdsUpdateHandler.promises.createFolder.resolves(null)
|
||||||
|
this.HttpErrorHandler.conflict.callsFake((req, res) => {
|
||||||
|
expect(req).to.equal(this.req)
|
||||||
|
expect(res).to.equal(this.res)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
this.TpdsController.updateFolder(this.req, this.res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('parseParams', function () {
|
describe('parseParams', function () {
|
||||||
it('should take the project name off the start and replace with slash', function () {
|
it('should take the project name off the start and replace with slash', function () {
|
||||||
const path = 'noSlashHere'
|
const path = 'noSlashHere'
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ describe('TpdsUpdateHandler', function () {
|
|||||||
this.source = 'dropbox'
|
this.source = 'dropbox'
|
||||||
this.path = `/some/file`
|
this.path = `/some/file`
|
||||||
this.update = {}
|
this.update = {}
|
||||||
|
this.folderPath = '/some/folder'
|
||||||
|
this.folder = {
|
||||||
|
_id: ObjectId(),
|
||||||
|
parentFolder_id: ObjectId(),
|
||||||
|
}
|
||||||
|
|
||||||
this.CooldownManager = {
|
this.CooldownManager = {
|
||||||
promises: {
|
promises: {
|
||||||
@@ -93,6 +98,7 @@ describe('TpdsUpdateHandler', function () {
|
|||||||
promises: {
|
promises: {
|
||||||
deleteUpdate: sinon.stub().resolves(),
|
deleteUpdate: sinon.stub().resolves(),
|
||||||
mergeUpdate: sinon.stub().resolves(),
|
mergeUpdate: sinon.stub().resolves(),
|
||||||
|
createFolder: sinon.stub().resolves(this.folder),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +287,69 @@ describe('TpdsUpdateHandler', function () {
|
|||||||
expectDropboxUnlinked()
|
expectDropboxUnlinked()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('getting a folder update', function () {
|
||||||
|
describe('with no matching project', function () {
|
||||||
|
setupMatchingProjects([])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectCreated()
|
||||||
|
expectFolderUpdateProcessed()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with one matching active project', function () {
|
||||||
|
setupMatchingProjects(['active1'])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectNotCreated()
|
||||||
|
expectFolderUpdateProcessed()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with one matching archived project', function () {
|
||||||
|
setupMatchingProjects(['archived1'])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectNotCreated()
|
||||||
|
expectFolderUpdateNotProcessed()
|
||||||
|
expectDropboxNotUnlinked()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with two matching active projects', function () {
|
||||||
|
setupMatchingProjects(['active1', 'active2'])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectNotCreated()
|
||||||
|
expectFolderUpdateNotProcessed()
|
||||||
|
expectDropboxUnlinked()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with two matching archived projects', function () {
|
||||||
|
setupMatchingProjects(['archived1', 'archived2'])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectNotCreated()
|
||||||
|
expectFolderUpdateNotProcessed()
|
||||||
|
expectDropboxNotUnlinked()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with one matching active and one matching archived project', function () {
|
||||||
|
setupMatchingProjects(['active1', 'archived1'])
|
||||||
|
receiveFolderUpdate()
|
||||||
|
expectProjectNotCreated()
|
||||||
|
expectFolderUpdateNotProcessed()
|
||||||
|
expectDropboxUnlinked()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('update to a project on cooldown', async function () {
|
||||||
|
setupMatchingProjects(['active1'])
|
||||||
|
setupProjectOnCooldown()
|
||||||
|
beforeEach(async function () {
|
||||||
|
await expect(
|
||||||
|
this.TpdsUpdateHandler.promises.createFolder(
|
||||||
|
this.userId,
|
||||||
|
this.projectName,
|
||||||
|
this.path
|
||||||
|
)
|
||||||
|
).to.be.rejectedWith(Errors.TooManyRequestsError)
|
||||||
|
})
|
||||||
|
expectFolderUpdateNotProcessed()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/* Setup helpers */
|
/* Setup helpers */
|
||||||
@@ -338,6 +407,16 @@ function receiveProjectDelete() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function receiveFolderUpdate() {
|
||||||
|
beforeEach(async function () {
|
||||||
|
await this.TpdsUpdateHandler.promises.createFolder(
|
||||||
|
this.userId,
|
||||||
|
this.projectName,
|
||||||
|
this.folderPath
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/* Expectations */
|
/* Expectations */
|
||||||
|
|
||||||
function expectProjectCreated() {
|
function expectProjectCreated() {
|
||||||
@@ -388,6 +467,21 @@ function expectUpdateNotProcessed() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function expectFolderUpdateProcessed() {
|
||||||
|
it('processes the folder update', function () {
|
||||||
|
expect(this.UpdateMerger.promises.createFolder).to.have.been.calledWith(
|
||||||
|
this.projects.active1._id,
|
||||||
|
this.folderPath
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectFolderUpdateNotProcessed() {
|
||||||
|
it("doesn't process the folder update", function () {
|
||||||
|
expect(this.UpdateMerger.promises.createFolder).not.to.have.been.called
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function expectDropboxUnlinked() {
|
function expectDropboxUnlinked() {
|
||||||
it('unlinks Dropbox', function () {
|
it('unlinks Dropbox', function () {
|
||||||
expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
|
expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
|
||||||
|
|||||||
Reference in New Issue
Block a user