From ed3a78451894eb54e2f9e3ba456986fd5cd6d2bb Mon Sep 17 00:00:00 2001 From: gohabereg Date: Tue, 19 Feb 2019 17:51:00 +0300 Subject: [PATCH] Cover all lines with tests --- src/app.js | 15 +- src/controllers/transport.js | 7 +- src/frontend/js/classes/editor.js | 4 +- src/frontend/js/modules/writing.js | 6 +- src/models/file.js | 11 ++ src/routes/api/pages.js | 8 +- src/routes/api/transport.js | 25 +-- src/routes/middlewares/pages.js | 5 +- src/utils/database/index.js | 2 +- src/utils/database/pagesOrder.js | 4 +- test/models/file.js | 27 ++++ test/rest/test_file.json | 3 + test/rest/test_image.png | Bin 0 -> 13263 bytes test/rest/transport.js | 250 +++++++++++++++++++++++++++++ yarn.lock | 23 ++- 15 files changed, 358 insertions(+), 32 deletions(-) create mode 100644 test/rest/test_file.json create mode 100644 test/rest/test_image.png create mode 100644 test/rest/transport.js diff --git a/src/app.js b/src/app.js index 65beda0..bb7b3aa 100644 --- a/src/app.js +++ b/src/app.js @@ -4,6 +4,7 @@ const path = require('path'); const cookieParser = require('cookie-parser'); const logger = require('morgan'); const rcParser = require('./utils/rcparser'); +const FileModel = require('./models/file'); const routes = require('./routes'); @@ -21,7 +22,19 @@ app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({extended: true})); app.use(cookieParser()); -app.use(express.static(path.join(__dirname, '../public'))); +app.use(express.static( + path.join(__dirname, '../public'), + { + setHeaders: async (res, pathToFile) => { + const filename = path.basename(pathToFile); + const file = await FileModel.getByFilename(filename); + + if (file._id && file.mimetype) { + res.setHeader('content-type', file.mimetype); + } + } + } +)); app.use('/', routes); // catch 404 and forward to error handler diff --git a/src/controllers/transport.js b/src/controllers/transport.js index 5cda4ab..4434fba 100644 --- a/src/controllers/transport.js +++ b/src/controllers/transport.js @@ -49,18 +49,19 @@ class Transport { */ static async fetch(url, map) { const fetchedFile = await fetch(url); - const buffer = await fetchedFile.buffer(); const filename = await random16(); fs.writeFileSync(`public/uploads/${filename}`, buffer); + const type = fileType(buffer); + const file = new Model({ name: url, filename, path: `/uploads/${filename}`, - size: buffer.size, - mimetype: fileType(buffer) + size: buffer.length, + mimetype: type ? type.mime : fetchedFile.headers.get('content-type') }); await file.save(); diff --git a/src/frontend/js/classes/editor.js b/src/frontend/js/classes/editor.js index 7308f86..8067055 100644 --- a/src/frontend/js/classes/editor.js +++ b/src/frontend/js/classes/editor.js @@ -47,9 +47,9 @@ export default class Editor { map: JSON.stringify({ path: 'file:url', size: 'file:size', - mimetype: 'file:mime', + mimetype: 'file:mime' }) - }, + } } } }, diff --git a/src/frontend/js/modules/writing.js b/src/frontend/js/modules/writing.js index e21e452..9ec392c 100644 --- a/src/frontend/js/modules/writing.js +++ b/src/frontend/js/modules/writing.js @@ -64,9 +64,10 @@ export default class Writing { if (this.nodes.removeButton) { this.nodes.removeButton.addEventListener('click', () => { - const isUserAgree = confirm("Are you sure?"); + const isUserAgree = confirm('Are you sure?'); + if (!isUserAgree) { - return + return; } this.removeButtonClicked(); @@ -115,6 +116,7 @@ export default class Writing { /** get ordering selector value */ let putAbovePageId = null; + if (this.nodes.putAboveIdSelector) { putAbovePageId = this.nodes.putAboveIdSelector.value; } diff --git a/src/models/file.js b/src/models/file.js index 883e500..e6932cf 100644 --- a/src/models/file.js +++ b/src/models/file.js @@ -34,6 +34,17 @@ class File { return new File(data); } + /** + * Find and return model of file with given id + * @param {string} filename - uploaded filename + * @returns {Promise} + */ + static async getByFilename(filename) { + const data = await filesDb.findOne({filename}); + + return new File(data); + } + /** * Find all files which match passed query object * diff --git a/src/routes/api/pages.js b/src/routes/api/pages.js index 89d1653..cacc420 100644 --- a/src/routes/api/pages.js +++ b/src/routes/api/pages.js @@ -3,12 +3,13 @@ const router = express.Router(); const multer = require('multer')(); const Pages = require('../../controllers/pages'); const PagesOrder = require('../../controllers/pagesOrder'); -const Aliases = require("../../controllers/aliases"); +const Aliases = require('../../controllers/aliases'); /** * GET /page/:id * * Return PageData of page with given id */ + router.get('/page/:id', async (req, res) => { try { const page = await Pages.get(req.params.id); @@ -118,12 +119,13 @@ router.delete('/page/:id', async (req, res) => { const pageAfterId = parentPageOrder.getPageAfter(page._id); let pageToRedirect; + if (pageBeforeId) { pageToRedirect = await Pages.get(pageBeforeId); } else if (pageAfterId) { pageToRedirect = await Pages.get(pageAfterId); } else { - pageToRedirect = page._parent !== "0" ? await Pages.get(page._parent) : null; + pageToRedirect = page._parent !== '0' ? await Pages.get(page._parent) : null; } /** @@ -134,8 +136,10 @@ router.delete('/page/:id', async (req, res) => { */ async function deleteRecursively(startFrom) { let order = []; + try { const children = await PagesOrder.get(startFrom); + order = children.order; } catch (e) {} diff --git a/src/routes/api/transport.js b/src/routes/api/transport.js index 57fb922..d4f0209 100644 --- a/src/routes/api/transport.js +++ b/src/routes/api/transport.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const multer = require('multer') +const multer = require('multer'); const Transport = require('../../controllers/transport'); /** @@ -16,14 +16,14 @@ const imageUploader = multer({ cb(null, true); } -}).fields([{name: 'image', maxCount: 1}]); +}).fields([ {name: 'image', maxCount: 1} ]); /** * Multer middleware for file uploading */ const fileUploader = multer({ - dest: 'public/uploads/', -}).fields([{name: 'file', maxCount: 1}]); + dest: 'public/uploads/' +}).fields([ {name: 'file', maxCount: 1} ]); /** * Accepts images to upload @@ -31,13 +31,16 @@ const fileUploader = multer({ router.post('/transport/image', imageUploader, async (req, res) => { let response = {success: 0}; - if (!req.files.image) { + if (!req.files || !req.files.image) { res.status(400).json(response); return; } try { - Object.assign(response, await Transport.save(req.files.image[0], JSON.parse(req.body.map))); + Object.assign( + response, + await Transport.save(req.files.image[0], req.body.map ? JSON.parse(req.body.map) : undefined) + ); response.success = 1; res.status(200).json(response); @@ -52,18 +55,20 @@ router.post('/transport/image', imageUploader, async (req, res) => { router.post('/transport/file', fileUploader, async (req, res) => { let response = {success: 0}; - if (!req.files.file) { + if (!req.files || !req.files.file) { res.status(400).json(response); return; } try { - Object.assign(response, await Transport.save(req.files.file[0], JSON.parse(req.body.map))); + Object.assign( + response, + await Transport.save(req.files.file[0], req.body.map ? JSON.parse(req.body.map) : undefined) + ); response.success = 1; res.status(200).json(response); } catch (e) { - console.log(e); res.status(500).json(response); } }); @@ -80,7 +85,7 @@ router.post('/transport/fetch', multer().none(), async (req, res) => { } try { - Object.assign(response, await Transport.fetch(req.body.url, JSON.parse(req.body.map))); + Object.assign(response, await Transport.fetch(req.body.url, req.body.map ? JSON.parse(req.body.map) : undefined)); response.success = 1; res.status(200).json(response); diff --git a/src/routes/middlewares/pages.js b/src/routes/middlewares/pages.js index 6e8ead8..a5480ec 100644 --- a/src/routes/middlewares/pages.js +++ b/src/routes/middlewares/pages.js @@ -31,7 +31,8 @@ async function createMenuTree(pages, level = 1, currentLevel = 1) { */ if (currentLevel !== level) { const children = await PagesOrder.get(pageId); - deepestChildren = await createMenuTree(children.order, level, currentLevel + 1) + + deepestChildren = await createMenuTree(children.order, level, currentLevel + 1); } } catch (e) {} @@ -56,8 +57,10 @@ module.exports = asyncMiddleware(async function (req, res, next) { * @type {string} */ const parentIdOfRootPages = '0'; + try { const rootPages = await PagesOrder.get(parentIdOfRootPages); + res.locals.menu = await createMenuTree(rootPages.order, 2); } catch (error) { console.log('Can not load menu:', error); diff --git a/src/utils/database/index.js b/src/utils/database/index.js index cbd1fb6..d6278e2 100644 --- a/src/utils/database/index.js +++ b/src/utils/database/index.js @@ -148,5 +148,5 @@ module.exports = { pages: new Database(pages), aliases: new Database(aliases), pagesOrder: new Database(pagesOrder), - files: new Database(files), + files: new Database(files) }; diff --git a/src/utils/database/pagesOrder.js b/src/utils/database/pagesOrder.js index 2c7324f..9edc028 100644 --- a/src/utils/database/pagesOrder.js +++ b/src/utils/database/pagesOrder.js @@ -7,7 +7,7 @@ const db = new Datastore({filename: `./${config.database}/pagesOrder.db`, autolo * Current DataStore preparation * Add initial row for RootPage */ -(async function() { +(async function () { const parentIdOfRootPages = '0'; const cbk = (resolve, reject) => (err, doc) => { if (err) { @@ -26,9 +26,9 @@ const db = new Datastore({filename: `./${config.database}/pagesOrder.db`, autolo page: '0', order: [] }; + await db.insert(initialData); } - }()); module.exports = db; diff --git a/test/models/file.js b/test/models/file.js index 4fa60a2..1e99b2e 100644 --- a/test/models/file.js +++ b/test/models/file.js @@ -171,6 +171,33 @@ describe('File model', () => { await file.destroy(); }); + it('Static getByFilename method', async () => { + const initialData = { + name: 'filename', + filename: 'randomname', + path: '/uploads/randomname', + size: 1024, + mimetype: 'image/png' + }; + + const file = new File(initialData); + + const savedFile = await file.save(); + + const foundFile = await File.getByFilename(savedFile.filename); + + const {data} = foundFile; + + expect(data._id).to.equal(savedFile._id); + expect(data.name).to.equal(savedFile.name); + expect(data.filename).to.equal(savedFile.filename); + expect(data.path).to.equal(savedFile.path); + expect(data.size).to.equal(savedFile.size); + expect(data.mimetype).to.equal(savedFile.mimetype); + + await file.destroy(); + }); + it('Static getAll method', async () => { const filesToSave = [ new File({ diff --git a/test/rest/test_file.json b/test/rest/test_file.json new file mode 100644 index 0000000..88c7f82 --- /dev/null +++ b/test/rest/test_file.json @@ -0,0 +1,3 @@ +{ + "Hello": "world" +} diff --git a/test/rest/test_image.png b/test/rest/test_image.png new file mode 100644 index 0000000000000000000000000000000000000000..28b7834c383436bfd9d13f78682e210fd1931a07 GIT binary patch literal 13263 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 literal 0 HcmV?d00001 diff --git a/test/rest/transport.js b/test/rest/transport.js new file mode 100644 index 0000000..9dac60f --- /dev/null +++ b/test/rest/transport.js @@ -0,0 +1,250 @@ +const fs = require('fs'); +const path = require('path'); +const fileType = require('file-type'); +const chai = require('chai'); +const chaiHTTP = require('chai-http'); +const {expect} = chai; + +const {app} = require('../../bin/www'); +const model = require('../../src/models/file'); + +const config = require('../../config'); + +chai.use(chaiHTTP); + +describe('Transport routes: ', () => { + let agent; + + before(async () => { + agent = chai.request.agent(app); + }); + + after(async () => { + const pathToDB = path.resolve(__dirname, '../../', config.database, './files.db'); + + if (fs.existsSync(pathToDB)) { + fs.unlinkSync(pathToDB); + } + }); + + it('Uploading an image', async () => { + const name = 'test_image.png'; + const image = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + const res = await agent + .post('/api/transport/image') + .attach('image', image, name); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file._id).to.equal(body._id); + expect(file.name).to.equal(name); + expect(file.filename).to.equal(body.filename); + expect(file.path).to.equal(body.path); + expect(file.mimetype).to.equal(fileType(image).mime); + expect(file.size).to.equal(image.byteLength); + + const getRes = await agent + .get(file.path); + + expect(getRes).to.have.status(200); + expect(getRes).to.have.header('content-type', fileType(image).mime); + }); + + it('Uploading an image with map option', async () => { + const name = 'test_image.png'; + const image = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + const res = await agent + .post('/api/transport/image') + .attach('image', image, name) + .field('map', JSON.stringify({_id: '_id', path: 'file:url', size: 'file:size', name: 'file:name'})); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file.name).to.equal(body.file.name); + expect(file.path).to.equal(body.file.url); + expect(file.size).to.equal(body.file.size); + }); + + it('Uploading a file', async () => { + const name = 'test_file.json'; + const json = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + const res = await agent + .post('/api/transport/file') + .attach('file', json, name); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file._id).to.equal(body._id); + expect(file.name).to.equal(name); + expect(file.filename).to.equal(body.filename); + expect(file.path).to.equal(body.path); + expect(file.size).to.equal(json.byteLength); + + const getRes = await agent + .get(file.path); + + expect(getRes).to.have.status(200); + expect(getRes).to.have.header('content-type', file.mimetype); + }); + + it('Uploading a file with map option', async () => { + const name = 'test_file.json'; + const json = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + const res = await agent + .post('/api/transport/file') + .attach('file', json, name) + .field('map', JSON.stringify({_id: '_id', path: 'file:url', size: 'file:size', name: 'file:name'})); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file.name).to.equal(body.file.name); + expect(file.path).to.equal(body.file.url); + expect(file.size).to.equal(body.file.size); + }); + + it('Send file URL to fetch', async () => { + const url = 'https://codex.so/public/app/img/codex-logo.svg'; + const res = await agent + .post('/api/transport/fetch') + .field('url', url); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file._id).to.equal(body._id); + expect(file.name).to.equal(body.name); + expect(file.filename).to.equal(body.filename); + expect(file.path).to.equal(body.path); + expect(file.size).to.equal(body.size); + + const getRes = await agent + .get(file.path); + + expect(getRes).to.have.status(200); + expect(getRes).to.have.header('content-type', file.mimetype); + }); + + it('Send an file URL to fetch with map option', async () => { + const url = 'https://codex.so/public/app/img/codex-logo.svg'; + const res = await agent + .post('/api/transport/fetch') + .field('url', url) + .field('map', JSON.stringify({_id: '_id', path: 'file:url', size: 'file:size', name: 'file:name'})); + + expect(res).to.have.status(200); + expect(res).to.be.json; + + const { body } = res; + + const file = await model.get(body._id); + + expect(body.success).to.equal(1); + expect(file.name).to.equal(body.file.name); + expect(file.path).to.equal(body.file.url); + expect(file.size).to.equal(body.file.size); + }); + + it('Negative tests for file uploading', async () => { + let res = await agent + .post('/api/transport/file') + .send(); + + let {body} = res; + + expect(res).to.have.status(400); + expect(body.success).to.equal(0); + + const name = 'test_file.json'; + const json = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + res = await agent + .post('/api/transport/file') + .attach('file', json, name) + .field('map', '{unvalid_json)'); + + body = res.body; + + expect(res).to.have.status(500); + expect(body.success).to.equal(0); + }); + + it('Negative tests for image uploading', async () => { + let res = await agent + .post('/api/transport/image') + .send(); + + let {body} = res; + + expect(res).to.have.status(400); + expect(body.success).to.equal(0); + + let name = 'test_file.json'; + const json = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + res = await agent + .post('/api/transport/image') + .attach('image', json, name); + + expect(res).to.have.status(400); + + name = 'test_image.png'; + const image = fs.readFileSync(path.resolve(`./test/rest/${name}`)); + res = await agent + .post('/api/transport/image') + .attach('image', image, name) + .field('map', '{unvalid_json)'); + + body = res.body; + + expect(res).to.have.status(500); + expect(body.success).to.equal(0); + }); + + it('Negative tests for file fetching', async () => { + let res = await agent + .post('/api/transport/fetch') + .send(); + + let {body} = res; + + expect(res).to.have.status(400); + expect(body.success).to.equal(0); + + const url = 'https://invalidurl'; + res = await agent + .post('/api/transport/fetch') + .field('url', url); + + body = res.body; + + expect(res).to.have.status(500); + expect(body.success).to.equal(0); + }).timeout(50000); +}); diff --git a/yarn.lock b/yarn.lock index b43e753..2595267 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2449,19 +2449,19 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= "eslint-config-codex@github:codex-team/eslint-config": - version "1.0.0" - resolved "https://codeload.github.com/codex-team/eslint-config/tar.gz/9082652b6059d6ec4cc8213811826fdfaad899b0" + version "1.1.0" + resolved "https://codeload.github.com/codex-team/eslint-config/tar.gz/a38c446d70463a125a610732a3a8931abac2152c" dependencies: - eslint-config-standard "^11.0.0" + eslint-config-standard "^12.0.0" eslint-plugin-import "^2.14.0" eslint-plugin-node "^7.0.1" eslint-plugin-promise "^3.8.0" eslint-plugin-standard "^3.0.1" -eslint-config-standard@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz#87ee0d3c9d95382dc761958cbb23da9eea31e0ba" - integrity sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw== +eslint-config-standard@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz#638b4c65db0bd5a41319f96bba1f15ddad2107d9" + integrity sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ== eslint-import-resolver-node@^0.3.1: version "0.3.2" @@ -6061,13 +6061,20 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1: +resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0: version "1.9.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== dependencies: path-parse "^1.0.6" +resolve@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== + dependencies: + path-parse "^1.0.6" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"