diff --git a/lib/index.js b/lib/index.js index deb7bdf..0333906 100644 --- a/lib/index.js +++ b/lib/index.js @@ -435,6 +435,74 @@ class Sharepoint { logAxiosError(this.debug, err, 'Unable to delete file') } } + + /** + * Moves the specified file + * @param options An object that must contain a 'fileName' (the name of the file), 'sourcePath' (the path to a folder in + * which the file is to be moved from) and 'targetPath' (the path to a folder which the file is to be moved to) properties. + * @returns {Promise} + */ + async moveFile (options) { + if (!options.fileName) { + throw new Error('You must provide a file name.') + } + + checkHeaders(this.accessToken) + + const sourcePath = encodeURIComponent(options.sourcePath) + const targetPath = encodeURIComponent(options.targetPath) + const fileName = encodeURIComponent(options.fileName) + + const formDigestValue = await getFormDigestValue(this.siteUrl, this.accessToken) + + const url = `${this.siteUrl}/_api/web/GetFileByServerRelativeUrl('${this.encodedBaseUrl}${sourcePath}/${fileName}')/moveto(newurl='${this.encodedBaseUrl}${targetPath}/${fileName}',flags=1)` + + try { + await axios({ + method: 'post', + url, + headers: { + Authorization: `Bearer ${this.accessToken}`, + 'X-RequestDigest': formDigestValue + } + }) + } catch (err) { + console.log(err) + logAxiosError(this.debug, err, 'Unable to move file') + } + } + + /** + * Moves the specified file + * @param options An object that must contain a 'sourcePath' (the path to a folder in + * which the file is to be moved from) and 'targetPath' (the path to a folder which the file is to be moved to) properties. + * @returns {Promise} + */ + async moveFolderContents (options) { + checkHeaders(this.accessToken) + + const filesToMove = [] + + async function collectFilesToMove (self, sourcePath, targetPath) { + const contents = await self.getContents(sourcePath) + for (const item of contents) { + if (item.__metadata.type === 'SP.File') { + filesToMove.push({ sourcePath, targetPath, fileName: item.Name }) + } else if (item.__metadata.type === 'SP.Folder') { + await collectFilesToMove(self, `${sourcePath}/${item.Name}`, `${targetPath}/${item.Name}`) + } + } + } + + await collectFilesToMove(this, options.sourcePath, options.targetPath) + + for (const { sourcePath, targetPath, fileName } of filesToMove) { + await this.createFolder(targetPath) + await this.moveFile({ sourcePath, targetPath, fileName }) + } + + await this.deleteFolder(options.sourcePath) + } } // based on https://axios-http.com/docs/handling_errors diff --git a/test/test.js b/test/test.js index 0c1c1a1..985e9be 100644 --- a/test/test.js +++ b/test/test.js @@ -384,6 +384,72 @@ describe('tests', function () { expect(contents.map(i => i.Name).includes(FOLDER_NAME3)).to.eql(false) expect(contents.map(i => i.Name).includes(FOLDER_NAME4)).to.eql(false) }) + + it('create and move a file', async () => { + const sourceFolderPath = `${process.env.SHAREPOINT_TESTS_DIR_PATH}/Source` + const targetFolderPath = `${process.env.SHAREPOINT_TESTS_DIR_PATH}/Target` + const fileName = 'the-file-to-move.txt' + const data = 'This file will be moved!' + + await sharepoint.createFolder(sourceFolderPath) + await sharepoint.createFolder(targetFolderPath) + await sharepoint.createFile({ path: sourceFolderPath, fileName, data }) + + // Check contents before + const sourceFolderContentsBefore = await sharepoint.getContents(sourceFolderPath) + expect(sourceFolderContentsBefore.length).to.eql(1) + expect(sourceFolderContentsBefore[0].Name).to.eql(fileName) + + const targetFolderContentsBefore = await sharepoint.getContents(targetFolderPath) + expect(targetFolderContentsBefore.length).to.eql(0) + + // Move file + await sharepoint.moveFile({ sourcePath: sourceFolderPath, targetPath: targetFolderPath, fileName }) + + // Check contents after + const sourceFolderContentsAfter = await sharepoint.getContents(sourceFolderPath) + expect(sourceFolderContentsAfter.length).to.eql(0) + + const targetFolderContentsAfter = await sharepoint.getContents(targetFolderPath) + expect(targetFolderContentsAfter.length).to.eql(1) + expect(targetFolderContentsAfter[0].Name).to.eql(fileName) + + await sharepoint.deleteFolder(sourceFolderPath) + await sharepoint.deleteFolder(targetFolderPath) + }) + + it('create and move a folder', async () => { + const sourceFolderPath = `${process.env.SHAREPOINT_TESTS_DIR_PATH}/Source` + const targetFolderPath = `${process.env.SHAREPOINT_TESTS_DIR_PATH}/Target` + + await sharepoint.createFolder(sourceFolderPath) + await sharepoint.createFolder(targetFolderPath) + await sharepoint.createFile({ path: sourceFolderPath, fileName: 'file-1.txt', data: 'File 1' }) + await sharepoint.createFile({ path: sourceFolderPath, fileName: 'file-2.txt', data: 'File 2' }) + await sharepoint.createFile({ path: sourceFolderPath, fileName: 'file-3.txt', data: 'File 3' }) + await sharepoint.createFolder(`${sourceFolderPath}/Nested Folder`) + await sharepoint.createFile({ path: `${sourceFolderPath}/Nested Folder`, fileName: 'file-4.txt', data: 'File 4' }) + await sharepoint.createFile({ path: `${sourceFolderPath}/Nested Folder`, fileName: 'file-5.txt', data: 'File 5' }) + + // Check contents before + const sourceFolderContentsBefore = await sharepoint.getContents(sourceFolderPath) + expect(sourceFolderContentsBefore.length).to.eql(4) + + const targetFolderContentsBefore = await sharepoint.getContents(targetFolderPath) + expect(targetFolderContentsBefore.length).to.eql(0) + + await sharepoint.moveFolderContents({ sourcePath: sourceFolderPath, targetPath: targetFolderPath }) + + // Check contents after + const sourceFolderContentsAfter = await sharepoint.getContents(sourceFolderPath) + expect(sourceFolderContentsAfter.length).to.eql(0) + + const targetFolderContentsAfter = await sharepoint.getContents(targetFolderPath) + expect(targetFolderContentsAfter.length).to.eql(4) + + await sharepoint.deleteFolder(sourceFolderPath) + await sharepoint.deleteFolder(targetFolderPath) + }) }) })