diff --git a/server/controllers/embed.controller.js b/server/controllers/embed.controller.js index bdbb221b..c1dc431a 100644 --- a/server/controllers/embed.controller.js +++ b/server/controllers/embed.controller.js @@ -1,8 +1,9 @@ import Project from '../models/project'; import escapeStringRegexp from 'escape-string-regexp'; const startTag = '@fs-'; +import { resolvePathToFile } from '../utils/filePath'; -function injectMediaUrls(filesToInject, mediaFiles, textFiles, projectId) { +function injectMediaUrls(filesToInject, allFiles, projectId) { filesToInject.forEach(file => { let fileStrings = file.content.match(/(['"])((\\\1|.)*?)\1/gm); const fileStringRegex = /^('|")(?!(http:\/\/|https:\/\/)).*('|")$/i; @@ -11,19 +12,20 @@ function injectMediaUrls(filesToInject, mediaFiles, textFiles, projectId) { //if string does not begin with http or https if (fileString.match(fileStringRegex)) { const filePath = fileString.substr(1, fileString.length - 2); - const filePathArray = filePath.split('/'); - const fileName = filePathArray[filePathArray.length - 1]; - mediaFiles.forEach(mediaFile => { - if (mediaFile.name === fileName) { - file.content = file.content.replace(filePath, mediaFile.url); - } - }); - if (textFiles) { - textFiles.forEach(textFile => { - if (textFile.name === fileName) { - file.content = file.content.replace(filePath, `/api/projects/${projectId}/${textFile.name}`); + const resolvedFile = resolvePathToFile(filePath, allFiles); + if (resolvedFile) { + if (resolvedFile.url) { + file.content = file.content.replace(filePath,resolvedFile.url); + } else if (resolvedFile.name.match(/(.+\.json$|.+\.txt$|.+\.csv$)/i)) { + let resolvedFilePath = filePath; + if (resolvedFilePath.startsWith('.')) { + resolvedFilePath = resolvedFilePath.substr(1); } - }); + while (resolvedFilePath.startsWith('/')) { + resolvedFilePath = resolvedFilePath.substr(1); + } + file.content = file.content.replace(filePath, `/api/projects/${projectId}/${resolvedFilePath}`); + } } } }); @@ -33,15 +35,14 @@ function injectMediaUrls(filesToInject, mediaFiles, textFiles, projectId) { export function serveProject(req, res) { Project.findById(req.params.project_id) .exec((err, project) => { + //TODO this does not parse html const files = project.files; let htmlFile = files.find(file => file.name.match(/\.html$/i)).content; const jsFiles = files.filter(file => file.name.match(/\.js$/i)); const cssFiles = files.filter(file => file.name.match(/\.css$/i)); - const mediaFiles = files.filter(file => file.url); - const textFiles = files.filter(file => file.name.match(/(.+\.json$|.+\.txt$|.+\.csv$)/i) && file.url === undefined); - injectMediaUrls(jsFiles, mediaFiles, textFiles, req.params.project_id); - injectMediaUrls(cssFiles, mediaFiles); + injectMediaUrls(jsFiles, files, req.params.project_id); + injectMediaUrls(cssFiles, files, req.params.project_id); jsFiles.forEach(jsFile => { const fileName = escapeStringRegexp(jsFile.name); diff --git a/server/controllers/file.controller.js b/server/controllers/file.controller.js index 428ddc5c..643c4b28 100644 --- a/server/controllers/file.controller.js +++ b/server/controllers/file.controller.js @@ -1,4 +1,5 @@ import Project from '../models/project'; +import { resolvePathToFile } from '../utils/filePath'; // Bug -> timestamps don't get created, but it seems like this will // be fixed in mongoose soon @@ -71,10 +72,11 @@ export function getFileContent(req, res) { if (err) { return res.status(404).send({success: false, message: 'Project with that id does not exist.'}); } - const file = project.files.find(file => file.name === req.params.file_name); - if (!file) { - return res.status(404).send({success: false, message: 'File with that name does not exist.'}); + const filePath = req.params[0]; + const resolvedFile = resolvePathToFile(filePath, project.files); + if (!resolvedFile) { + return res.status(404).send({success: false, message: 'File with that name and path does not exist.'}); } - res.send(file.content); + res.send(resolvedFile.content); }); } diff --git a/server/routes/file.routes.js b/server/routes/file.routes.js index d4fb5764..8a881057 100644 --- a/server/routes/file.routes.js +++ b/server/routes/file.routes.js @@ -5,6 +5,6 @@ const router = new Router(); router.route('/projects/:project_id/files').post(FileController.createFile); router.route('/projects/:project_id/files/:file_id').delete(FileController.deleteFile); -router.route('/projects/:project_id/:file_name').get(FileController.getFileContent); +router.route('/projects/:project_id/*?').get(FileController.getFileContent); export default router; \ No newline at end of file diff --git a/server/utils/filePath.js b/server/utils/filePath.js new file mode 100644 index 00000000..4434daf1 --- /dev/null +++ b/server/utils/filePath.js @@ -0,0 +1,38 @@ +export function resolvePathToFile(filePath, files) { + const filePathArray = filePath.split('/'); + let resolvedFile; + let currentFile; + filePathArray.some((filePathSegment, index) => { + if (filePathSegment === "" || filePathSegment === ".") { + return false; + } else if (filePathSegment === "..") { + return true; + } else { + if (!currentFile) { + const file = files.find(file => file.name === filePathSegment); + if (!file) { + return true; + } + currentFile = file; + if (index === filePathArray.length - 1) { + resolvedFile = file; + } + } else { + const childFiles = currentFile.children.map(childFileId => { + return files.find(file => { + return file._id.valueOf().toString() === childFileId.valueOf(); + }); + }); + childFiles.some(childFile => { + if (childFile.name === filePathSegment) { + currentFile = childFile; + if (index === filePathArray.length - 1) { + resolvedFile = childFile; + } + } + }); + } + } + }); + return resolvedFile; +} \ No newline at end of file