From 26d65396b46325fb2690afffe5908a44d21149ba Mon Sep 17 00:00:00 2001 From: Gaurang Tandon <1gaurangtandon@gmail.com> Date: Sat, 15 Dec 2018 12:35:52 +0530 Subject: [PATCH 1/4] fixes #568 --- server/controllers/project.controller.js | 4 ++-- server/models/project.js | 4 ++-- server/utils/generateSlug.js | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 server/utils/generateSlug.js diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js index 88b990a3..0a98d253 100644 --- a/server/controllers/project.controller.js +++ b/server/controllers/project.controller.js @@ -2,8 +2,8 @@ import archiver from 'archiver'; import request from 'request'; import moment from 'moment'; import isUrl from 'is-url'; -import slugify from 'slugify'; import jsdom, { serializeDocument } from 'jsdom'; +import generateSlug from '../utils/generateSlug'; import Project from '../models/project'; import User from '../models/user'; import { deleteObjectsFromS3, getObjectKey } from './aws.controller'; @@ -294,7 +294,7 @@ function buildZip(project, req, res) { }); const currentTime = moment().format('YYYY_MM_DD_HH_mm_ss'); - project.slug = slugify(project.name, '_'); + project.slug = generateSlug(project.name, '_'); res.attachment(`${project.slug}_${currentTime}.zip`); zip.pipe(res); diff --git a/server/models/project.js b/server/models/project.js index c1a255d8..23b93796 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -1,6 +1,6 @@ import mongoose from 'mongoose'; import shortid from 'shortid'; -import slugify from 'slugify'; +import generateSlug from '../utils/generateSlug'; const { Schema } = mongoose; @@ -40,7 +40,7 @@ projectSchema.set('toJSON', { projectSchema.pre('save', function generateSlug(next) { const project = this; - project.slug = slugify(project.name, '_'); + project.slug = generateSlug(project.name, '_'); return next(); }); diff --git a/server/utils/generateSlug.js b/server/utils/generateSlug.js new file mode 100644 index 00000000..0e67b8a2 --- /dev/null +++ b/server/utils/generateSlug.js @@ -0,0 +1,16 @@ +/** + * generate short slug for a given string + * that can be used as a valid file name + * in all operating systems + * @param {String} string + * @param {String} replacer (optional) character to replace invalid characters + */ +export function generateSlug(string, replacer) { + // from here https://serverfault.com/a/242134 + const INVALID_CHARS_REGEX = /[*/?:\\<>|"\u0000-\u001F]/g; + const slug = string.replace(INVALID_CHARS_REGEX, replacer || ''); + + return slug; +} + +export default generateSlug; From d86944034e70f6223a1462668f67f6bcc81e765d Mon Sep 17 00:00:00 2001 From: Gaurang Tandon <1gaurangtandon@gmail.com> Date: Sat, 15 Dec 2018 12:43:58 +0530 Subject: [PATCH 2/4] fix lint errors --- server/models/project.js | 40 +++++++++++++++++++++--------------- server/utils/generateSlug.js | 2 +- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/server/models/project.js b/server/models/project.js index 23b93796..742c9667 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -4,14 +4,17 @@ import generateSlug from '../utils/generateSlug'; const { Schema } = mongoose; -const fileSchema = new Schema({ - name: { type: String, default: 'sketch.js' }, - content: { type: String, default: '' }, - url: { type: String }, - children: { type: [String], default: [] }, - fileType: { type: String, default: 'file' }, - isSelectedFile: { type: Boolean } -}, { timestamps: true, _id: true, usePushEach: true }); +const fileSchema = new Schema( + { + name: { type: String, default: 'sketch.js' }, + content: { type: String, default: '' }, + url: { type: String }, + children: { type: [String], default: [] }, + fileType: { type: String, default: 'file' }, + isSelectedFile: { type: Boolean } + }, + { timestamps: true, _id: true, usePushEach: true } +); fileSchema.virtual('id').get(function getFileId() { return this._id.toHexString(); @@ -21,14 +24,17 @@ fileSchema.set('toJSON', { virtuals: true }); -const projectSchema = new Schema({ - name: { type: String, default: "Hello p5.js, it's the server" }, - user: { type: Schema.Types.ObjectId, ref: 'User' }, - serveSecure: { type: Boolean, default: false }, - files: { type: [fileSchema] }, - _id: { type: String, default: shortid.generate }, - slug: { type: String } -}, { timestamps: true, usePushEach: true }); +const projectSchema = new Schema( + { + name: { type: String, default: "Hello p5.js, it's the server" }, + user: { type: Schema.Types.ObjectId, ref: 'User' }, + serveSecure: { type: Boolean, default: false }, + files: { type: [fileSchema] }, + _id: { type: String, default: shortid.generate }, + slug: { type: String } + }, + { timestamps: true, usePushEach: true } +); projectSchema.virtual('id').get(function getProjectId() { return this._id; @@ -38,7 +44,7 @@ projectSchema.set('toJSON', { virtuals: true }); -projectSchema.pre('save', function generateSlug(next) { +projectSchema.pre('save', function slugGenerator(next) { const project = this; project.slug = generateSlug(project.name, '_'); return next(); diff --git a/server/utils/generateSlug.js b/server/utils/generateSlug.js index 0e67b8a2..19177e17 100644 --- a/server/utils/generateSlug.js +++ b/server/utils/generateSlug.js @@ -5,7 +5,7 @@ * @param {String} string * @param {String} replacer (optional) character to replace invalid characters */ -export function generateSlug(string, replacer) { +function generateSlug(string, replacer) { // from here https://serverfault.com/a/242134 const INVALID_CHARS_REGEX = /[*/?:\\<>|"\u0000-\u001F]/g; const slug = string.replace(INVALID_CHARS_REGEX, replacer || ''); From 0f1dfef3c813a3dfe76f88025434be44f3d43abd Mon Sep 17 00:00:00 2001 From: Gaurang Tandon <1gaurangtandon@gmail.com> Date: Sat, 15 Dec 2018 12:46:35 +0530 Subject: [PATCH 3/4] remove slugify from dependencies --- package.json | 285 +++++++++++++++++++++++++-------------------------- 1 file changed, 142 insertions(+), 143 deletions(-) diff --git a/package.json b/package.json index 8c68b1f3..437cfae0 100644 --- a/package.json +++ b/package.json @@ -1,145 +1,144 @@ { - "name": "p5.js-web-editor", - "version": "0.0.1", - "description": "The web editor for p5.js.", - "scripts": { - "clean": "rimraf dist", - "start": "cross-env BABEL_DISABLE_CACHE=1 NODE_ENV=development nodemon index.js", - "start:prod": "cross-env NODE_ENV=production node index.js", - "lint": "eslint client server --ext .jsx --ext .js", - "lint-fix": "eslint client server --ext .jsx --ext .js --fix", - "build": "npm run build:client && npm run build:server && npm run build:examples", - "build:client": "cross-env NODE_ENV=production webpack --config webpack/config.prod.js", - "build:server": "cross-env NODE_ENV=production webpack --config webpack/config.server.js", - "build:examples": "cross-env NODE_ENV=production webpack --config webpack/config.examples.js", - "test": "npm run lint", - "fetch-examples": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples.js", - "fetch-examples-gg": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples-gg.js", - "fetch-examples:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples.bundle.js", - "fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js" - }, - "main": "index.js", - "author": "Cassie Tarakajian", - "license": "LGPL-2.1", - "repository": { - "type": "git", - "url": "git+https://github.com/catarak/p5.js-web-editor.git" - }, - "devDependencies": { - "babel-eslint": "^7.1.1", - "babel-loader": "^7.1.4", - "babel-plugin-transform-react-constant-elements": "^6.8.0", - "babel-plugin-transform-react-inline-elements": "^6.8.0", - "babel-plugin-transform-react-remove-prop-types": "^0.2.6", - "babel-plugin-webpack-loaders": "^0.9.0", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.5.0", - "babel-preset-react-optimize": "^1.0.1", - "babel-preset-stage-0": "^6.5.0", - "chunk-manifest-webpack-plugin": "^1.1.2", - "css-loader": "^0.23.1", - "cssnano": "^3.7.1", - "eslint": "^4.9.0", - "eslint-config-airbnb": "^16.1.0", - "eslint-plugin-import": "^2.2.0", - "eslint-plugin-jsx-a11y": "^6.0.3", - "eslint-plugin-react": "^7.7.0", - "extract-text-webpack-plugin": "^3.0.2", - "file-loader": "^2.0.0", - "node-sass": "^4.9.0", - "nodemon": "^1.9.2", - "postcss-cssnext": "^2.7.0", - "postcss-focus": "^1.0.0", - "postcss-loader": "^0.9.1", - "postcss-reporter": "^1.3.3", - "rimraf": "^2.6.2", - "sass-loader": "^6.0.6", - "style-loader": "^0.13.1", - "webpack-manifest-plugin": "^2.0.0", - "webpack-node-externals": "^1.7.2" - }, - "engines": { - "node": ">=8.9.0" - }, - "dependencies": { - "archiver": "^1.1.0", - "async": "^2.0.0", - "axios": "^0.12.0", - "babel-core": "^6.26.0", - "babel-polyfill": "^6.8.0", - "babel-register": "^6.8.0", - "bcrypt-nodejs": "0.0.3", - "blob-util": "^1.2.1", - "body-parser": "^1.15.1", - "bson-objectid": "^1.1.4", - "classnames": "^2.2.5", - "clipboard": "^1.7.1", - "codemirror": "^5.38.0", - "connect-mongo": "^1.2.0", - "console-feed": "^2.8.1", - "cookie-parser": "^1.4.1", - "cors": "^2.8.1", - "cross-env": "^5.1.3", - "csslint": "^0.10.0", - "decomment": "^0.8.7", - "dotenv": "^2.0.0", - "dropzone": "^4.3.0", - "escape-string-regexp": "^1.0.5", - "eslint-loader": "^1.3.0", - "express": "^4.13.4", - "express-basic-auth": "^1.1.5", - "express-session": "^1.13.0", - "htmlhint": "^0.9.13", - "is-url": "^1.2.2", - "js-beautify": "^1.6.4", - "jsdom": "^9.8.3", - "jshint": "^2.9.4", - "lodash": "^4.16.4", - "loop-protect": "github:catarak/loop-protect", - "mjml": "^3.3.2", - "moment": "^2.14.1", - "mongoose": "^4.6.8", - "node-uuid": "^1.4.7", - "nodemailer": "^2.6.4", - "nodemailer-mailgun-transport": "^1.2.2", - "passport": "^0.3.2", - "passport-github": "^1.1.0", - "passport-google-oauth20": "^1.0.0", - "passport-local": "^1.0.0", - "pretty-bytes": "^3.0.1", - "primer-tooltips": "^1.4.1", - "project-name-generator": "^2.1.3", - "prop-types": "^15.6.0", - "q": "^1.4.1", - "react": "^16.4.0", - "react-dom": "^16.4.0", - "react-helmet": "^5.1.3", - "react-hot-loader": "^4.1.2", - "react-inlinesvg": "^0.7.5", - "react-redux": "^5.0.6", - "react-router": "^3.2.0", - "react-split-pane": "^0.1.44", - "react-tabs": "^2.2.1", - "redux": "^3.5.2", - "redux-devtools": "^3.4.1", - "redux-devtools-dock-monitor": "^1.1.3", - "redux-devtools-log-monitor": "^1.4.0", - "redux-form": "^5.3.3", - "redux-thunk": "^2.1.0", - "request": "^2.76.0", - "request-promise": "^4.1.1", - "s3": "^4.4.0", - "s3-policy": "^0.2.0", - "sass-extract": "^2.1.0", - "sass-extract-js": "^0.4.0", - "sass-extract-loader": "^1.1.0", - "shortid": "^2.2.6", - "slugify": "^1.2.9", - "srcdoc-polyfill": "^0.2.0", - "url": "^0.11.0", - "webpack": "^3.1.0", - "webpack-dev-middleware": "^2.0.6", - "webpack-hot-middleware": "^2.10.0", - "xhr": "^2.2.1" - } + "name": "p5.js-web-editor", + "version": "0.0.1", + "description": "The web editor for p5.js.", + "scripts": { + "clean": "rimraf dist", + "start": "cross-env BABEL_DISABLE_CACHE=1 NODE_ENV=development nodemon index.js", + "start:prod": "cross-env NODE_ENV=production node index.js", + "lint": "eslint client server --ext .jsx --ext .js", + "lint-fix": "eslint client server --ext .jsx --ext .js --fix", + "build": "npm run build:client && npm run build:server && npm run build:examples", + "build:client": "cross-env NODE_ENV=production webpack --config webpack/config.prod.js", + "build:server": "cross-env NODE_ENV=production webpack --config webpack/config.server.js", + "build:examples": "cross-env NODE_ENV=production webpack --config webpack/config.examples.js", + "test": "npm run lint", + "fetch-examples": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples.js", + "fetch-examples-gg": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples-gg.js", + "fetch-examples:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples.bundle.js", + "fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js" + }, + "main": "index.js", + "author": "Cassie Tarakajian", + "license": "LGPL-2.1", + "repository": { + "type": "git", + "url": "git+https://github.com/catarak/p5.js-web-editor.git" + }, + "devDependencies": { + "babel-eslint": "^7.1.1", + "babel-loader": "^7.1.4", + "babel-plugin-transform-react-constant-elements": "^6.8.0", + "babel-plugin-transform-react-inline-elements": "^6.8.0", + "babel-plugin-transform-react-remove-prop-types": "^0.2.6", + "babel-plugin-webpack-loaders": "^0.9.0", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.5.0", + "babel-preset-react-optimize": "^1.0.1", + "babel-preset-stage-0": "^6.5.0", + "chunk-manifest-webpack-plugin": "^1.1.2", + "css-loader": "^0.23.1", + "cssnano": "^3.7.1", + "eslint": "^4.9.0", + "eslint-config-airbnb": "^16.1.0", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jsx-a11y": "^6.0.3", + "eslint-plugin-react": "^7.7.0", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^2.0.0", + "node-sass": "^4.9.0", + "nodemon": "^1.9.2", + "postcss-cssnext": "^2.7.0", + "postcss-focus": "^1.0.0", + "postcss-loader": "^0.9.1", + "postcss-reporter": "^1.3.3", + "rimraf": "^2.6.2", + "sass-loader": "^6.0.6", + "style-loader": "^0.13.1", + "webpack-manifest-plugin": "^2.0.0", + "webpack-node-externals": "^1.7.2" + }, + "engines": { + "node": ">=8.9.0" + }, + "dependencies": { + "archiver": "^1.1.0", + "async": "^2.0.0", + "axios": "^0.12.0", + "babel-core": "^6.26.0", + "babel-polyfill": "^6.8.0", + "babel-register": "^6.8.0", + "bcrypt-nodejs": "0.0.3", + "blob-util": "^1.2.1", + "body-parser": "^1.15.1", + "bson-objectid": "^1.1.4", + "classnames": "^2.2.5", + "clipboard": "^1.7.1", + "codemirror": "^5.38.0", + "connect-mongo": "^1.2.0", + "console-feed": "^2.8.1", + "cookie-parser": "^1.4.1", + "cors": "^2.8.1", + "cross-env": "^5.1.3", + "csslint": "^0.10.0", + "decomment": "^0.8.7", + "dotenv": "^2.0.0", + "dropzone": "^4.3.0", + "escape-string-regexp": "^1.0.5", + "eslint-loader": "^1.3.0", + "express": "^4.13.4", + "express-basic-auth": "^1.1.5", + "express-session": "^1.13.0", + "htmlhint": "^0.9.13", + "is-url": "^1.2.2", + "js-beautify": "^1.6.4", + "jsdom": "^9.8.3", + "jshint": "^2.9.4", + "lodash": "^4.16.4", + "loop-protect": "github:catarak/loop-protect", + "mjml": "^3.3.2", + "moment": "^2.14.1", + "mongoose": "^4.6.8", + "node-uuid": "^1.4.7", + "nodemailer": "^2.6.4", + "nodemailer-mailgun-transport": "^1.2.2", + "passport": "^0.3.2", + "passport-github": "^1.1.0", + "passport-google-oauth20": "^1.0.0", + "passport-local": "^1.0.0", + "pretty-bytes": "^3.0.1", + "primer-tooltips": "^1.4.1", + "project-name-generator": "^2.1.3", + "prop-types": "^15.6.0", + "q": "^1.4.1", + "react": "^16.4.0", + "react-dom": "^16.4.0", + "react-helmet": "^5.1.3", + "react-hot-loader": "^4.1.2", + "react-inlinesvg": "^0.7.5", + "react-redux": "^5.0.6", + "react-router": "^3.2.0", + "react-split-pane": "^0.1.44", + "react-tabs": "^2.2.1", + "redux": "^3.5.2", + "redux-devtools": "^3.4.1", + "redux-devtools-dock-monitor": "^1.1.3", + "redux-devtools-log-monitor": "^1.4.0", + "redux-form": "^5.3.3", + "redux-thunk": "^2.1.0", + "request": "^2.76.0", + "request-promise": "^4.1.1", + "s3": "^4.4.0", + "s3-policy": "^0.2.0", + "sass-extract": "^2.1.0", + "sass-extract-js": "^0.4.0", + "sass-extract-loader": "^1.1.0", + "shortid": "^2.2.6", + "srcdoc-polyfill": "^0.2.0", + "url": "^0.11.0", + "webpack": "^3.1.0", + "webpack-dev-middleware": "^2.0.6", + "webpack-hot-middleware": "^2.10.0", + "xhr": "^2.2.1" + } } From bd3eed5fd35f5cf4f85202ccfff5ad67ed321261 Mon Sep 17 00:00:00 2001 From: Gaurang Tandon <1gaurangtandon@gmail.com> Date: Sun, 10 Feb 2019 06:57:03 +0530 Subject: [PATCH 4/4] reverted some changes and changed to file system safe naming --- package-lock.json | 62 +++++++++++++------ package.json | 1 + server/controllers/project.controller.js | 7 ++- server/models/project.js | 6 +- ...eSlug.js => generateFileSystemSafeName.js} | 6 +- 5 files changed, 54 insertions(+), 28 deletions(-) rename server/utils/{generateSlug.js => generateFileSystemSafeName.js} (71%) diff --git a/package-lock.json b/package-lock.json index 260b5ed2..02bf81cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1190,7 +1190,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, "source-map": { @@ -15665,12 +15665,14 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -15690,7 +15692,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -15838,6 +15841,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -17750,7 +17754,7 @@ }, "jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, @@ -19631,7 +19635,8 @@ "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "optional": true }, "caseless": { "version": "0.12.0", @@ -19648,12 +19653,14 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true }, "combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -19666,12 +19673,14 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "optional": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "optional": true }, "cryptiles": { "version": "2.0.5", @@ -19716,7 +19725,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "optional": true }, "delegates": { "version": "1.0.0", @@ -19748,7 +19758,8 @@ "extsprintf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "optional": true }, "forever-agent": { "version": "0.6.1", @@ -19918,6 +19929,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -19931,7 +19943,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true }, "isstream": { "version": "0.1.2", @@ -20004,12 +20017,14 @@ "mime-db": { "version": "1.27.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", + "optional": true }, "mime-types": { "version": "2.1.15", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "optional": true, "requires": { "mime-db": "~1.27.0" } @@ -20085,7 +20100,8 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "optional": true }, "oauth-sign": { "version": "0.8.2", @@ -20143,7 +20159,8 @@ "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "optional": true }, "punycode": { "version": "1.4.1", @@ -20181,6 +20198,7 @@ "version": "2.2.9", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "optional": true, "requires": { "buffer-shims": "~1.0.0", "core-util-is": "~1.0.0", @@ -20289,6 +20307,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -20299,6 +20318,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=", + "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -20382,7 +20402,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "optional": true }, "uuid": { "version": "3.0.1", @@ -22726,7 +22747,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", - "dev": true + "dev": true, + "optional": true }, "ansi-styles": { "version": "2.2.1", @@ -22836,6 +22858,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -23305,6 +23328,7 @@ "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-4.0.0.tgz", "integrity": "sha1-qvVwsqsL+w3abW6TKR1UswsffSI=", "dev": true, + "optional": true, "requires": { "lodash.tostring": "^4.0.0" } @@ -29053,9 +29077,9 @@ "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, "slugify": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.2.9.tgz", - "integrity": "sha512-n0cdJ+kN3slJu8SbZXt/EHjljBqF6MxvMGSg/NPpBzoY7yyXoH38wp/ox20a1JaG1KgmdTN5Lf3aS9+xB2Y2aQ==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", + "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==" }, "snapdragon": { "version": "0.8.2", diff --git a/package.json b/package.json index 437cfae0..3f92b09a 100644 --- a/package.json +++ b/package.json @@ -134,6 +134,7 @@ "sass-extract-js": "^0.4.0", "sass-extract-loader": "^1.1.0", "shortid": "^2.2.6", + "slugify": "^1.3.4", "srcdoc-polyfill": "^0.2.0", "url": "^0.11.0", "webpack": "^3.1.0", diff --git a/server/controllers/project.controller.js b/server/controllers/project.controller.js index 0a98d253..15e9b3ee 100644 --- a/server/controllers/project.controller.js +++ b/server/controllers/project.controller.js @@ -2,8 +2,9 @@ import archiver from 'archiver'; import request from 'request'; import moment from 'moment'; import isUrl from 'is-url'; +import slugify from 'slugify'; import jsdom, { serializeDocument } from 'jsdom'; -import generateSlug from '../utils/generateSlug'; +import generateFileSystemSafeName from '../utils/generateFileSystemSafeName'; import Project from '../models/project'; import User from '../models/user'; import { deleteObjectsFromS3, getObjectKey } from './aws.controller'; @@ -294,8 +295,8 @@ function buildZip(project, req, res) { }); const currentTime = moment().format('YYYY_MM_DD_HH_mm_ss'); - project.slug = generateSlug(project.name, '_'); - res.attachment(`${project.slug}_${currentTime}.zip`); + project.slug = slugify(project.name, '_'); + res.attachment(`${generateFileSystemSafeName(project.slug)}_${currentTime}.zip`); zip.pipe(res); function addFileToZip(file, path) { diff --git a/server/models/project.js b/server/models/project.js index 742c9667..e3c22bdb 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -1,6 +1,6 @@ import mongoose from 'mongoose'; import shortid from 'shortid'; -import generateSlug from '../utils/generateSlug'; +import slugify from 'slugify'; const { Schema } = mongoose; @@ -44,9 +44,9 @@ projectSchema.set('toJSON', { virtuals: true }); -projectSchema.pre('save', function slugGenerator(next) { +projectSchema.pre('save', function generateSlug(next) { const project = this; - project.slug = generateSlug(project.name, '_'); + project.slug = slugify(project.name, '_'); return next(); }); diff --git a/server/utils/generateSlug.js b/server/utils/generateFileSystemSafeName.js similarity index 71% rename from server/utils/generateSlug.js rename to server/utils/generateFileSystemSafeName.js index 19177e17..2eeef579 100644 --- a/server/utils/generateSlug.js +++ b/server/utils/generateFileSystemSafeName.js @@ -1,11 +1,11 @@ /** - * generate short slug for a given string + * generate file system safe string for a given string * that can be used as a valid file name * in all operating systems * @param {String} string * @param {String} replacer (optional) character to replace invalid characters */ -function generateSlug(string, replacer) { +function generateFileSystemSafeName(string, replacer) { // from here https://serverfault.com/a/242134 const INVALID_CHARS_REGEX = /[*/?:\\<>|"\u0000-\u001F]/g; const slug = string.replace(INVALID_CHARS_REGEX, replacer || ''); @@ -13,4 +13,4 @@ function generateSlug(string, replacer) { return slug; } -export default generateSlug; +export default generateFileSystemSafeName;