├── Procfile ├── scripts ├── start-mongod.sh ├── generate-a11y-report.js ├── generate-development-doc.js ├── postinstall.js ├── nodejs-change-version.sh ├── unset-proxies.sh ├── generate-changelog.js ├── set-proxies.sh ├── update-meanstackjs.js ├── generate-ssl-certs.sh ├── mongodb-install.sh └── nodejs-install.sh ├── client ├── images │ ├── mean.png │ ├── agenda.png │ ├── nodejs.png │ ├── plato.png │ ├── angularjs.png │ ├── expressjs.png │ ├── favicon.ico │ ├── logo │ │ ├── icon.png │ │ ├── header.png │ │ ├── icon2x.png │ │ ├── icon3x.png │ │ ├── favicon.ico │ │ ├── header2x.png │ │ ├── header3x.png │ │ ├── iconword.png │ │ ├── darkheader.png │ │ ├── iconword2x.png │ │ ├── iconword3x.png │ │ ├── darkheader2x.png │ │ ├── darkheader3x.png │ │ ├── darkiconword.png │ │ ├── darkiconword 2x.png │ │ └── darkiconword 3x.png │ ├── mongodb.png │ ├── swagger.png │ ├── nightwatch.png │ ├── 404pinkybrain.gif │ ├── greenpioneer.png │ └── mongoexpress.png ├── modules │ ├── blog │ │ ├── blog.style.css │ │ ├── blog.module.js │ │ ├── blog.factory.js │ │ ├── blog.style.scss │ │ ├── blog.style.less │ │ ├── view.view.html │ │ ├── list.view.html │ │ ├── blog.routes.js │ │ ├── create.view.html │ │ ├── edit.view.html │ │ └── blog.controller.js │ ├── admin │ │ ├── admin.module.js │ │ ├── admin.style.scss │ │ ├── log.view.html │ │ ├── admin.routes.js │ │ ├── admin.spec.js │ │ ├── admin.factory.js │ │ ├── users.view.html │ │ ├── admin.controller.js │ │ ├── errors.view.html │ │ └── messages.view.html │ ├── chat │ │ ├── chat.module.js │ │ ├── chat.routes.js │ │ ├── chat.view.html │ │ └── chat.controller.js │ ├── index │ │ ├── index.module.js │ │ ├── index.style.less │ │ ├── index.controller.js │ │ ├── index.routes.js │ │ ├── index.spec.js │ │ ├── index.style.scss │ │ └── index.style.css │ ├── user │ │ ├── user.module.js │ │ ├── forgot.view.html │ │ ├── signin.view.html │ │ ├── user.routes.js │ │ ├── reset.view.html │ │ └── user.controller.js │ ├── footer │ │ ├── footer.module.js │ │ ├── footer.style.scss │ │ ├── footer.view.html │ │ ├── footer.controller.js │ │ └── footer.spec.js │ ├── header │ │ ├── header.module.js │ │ ├── header.controller.js │ │ └── header.spec.js │ ├── core │ │ ├── core.view.html │ │ ├── debug.view.html │ │ ├── core.module.js │ │ ├── core.controller.js │ │ ├── util.config.js │ │ ├── core.directive.js │ │ ├── storage.factory.js │ │ ├── core.config.js │ │ ├── core.route.js │ │ ├── 404.view.html │ │ ├── 500.view.html │ │ └── core.factory.js │ └── client.module.js └── styles │ └── global.style.scss ├── commands ├── blank │ ├── client │ │ ├── module.js │ │ ├── spec.js │ │ ├── view.view.html │ │ ├── style.scss │ │ ├── factory.js │ │ ├── controller.js │ │ └── routes.js │ └── server │ │ ├── socket.js │ │ ├── spec.js │ │ ├── controller.js │ │ ├── model.js │ │ └── routes.js └── template │ ├── client │ ├── module.js │ ├── factory.js │ ├── style.scss │ ├── view.view.html │ ├── list.view.html │ ├── routes.js │ ├── create.view.html │ ├── edit.view.html │ └── controller.js │ └── server │ ├── socket.js │ ├── model.js │ ├── spec.js │ ├── routes.js │ └── controller.js ├── documentation ├── _Footer.md ├── Servers.md ├── Tools.md ├── Scripts.md ├── Testing.md ├── CLI.md ├── File-Naming-Structure.md ├── Roadmap.md ├── FAQ.md ├── Errors.md ├── Getting-Started.md └── Development-Document.md ├── server ├── modules │ ├── chat │ │ ├── chat.controller.js │ │ └── chat.socket.js │ ├── system │ │ ├── setting.view.pug │ │ ├── system.routes.js │ │ ├── system.spec.js │ │ └── system.controller.js │ ├── admin │ │ ├── error.model.js │ │ ├── admin.spec.js │ │ └── admin.routes.js │ ├── blog │ │ ├── blog.model.js │ │ ├── blog.routes.js │ │ └── blog.spec.js │ └── users │ │ └── users.spec.js ├── headers.js ├── tools.js ├── mail.js ├── cdn.js ├── db.js ├── authentication.js ├── config.js ├── security.js ├── prerenderer.js ├── token.js ├── logger.js ├── seo.js ├── routes.js ├── error.js └── middleware.js ├── .nodemonignore ├── index.js ├── configs ├── environment.js ├── certificates │ ├── certExample.pem │ └── keyExample.pem ├── seo.js └── environments │ ├── test.js │ ├── development.js │ ├── production.js │ └── nightwatch.js ├── tools ├── mongo_express │ ├── index.js │ └── package.json ├── swagger │ ├── modules │ │ ├── users │ │ │ ├── models.js │ │ │ └── services.js │ │ └── blogs │ │ │ ├── services.js │ │ │ └── models.js │ └── package.json ├── nightwatch │ ├── index.js │ └── package.json ├── plato │ ├── package.json │ └── index.js ├── agenda │ ├── package.json │ └── index.js └── livereload │ ├── package.json │ └── server.livereload.js ├── tests ├── unit │ ├── mocha.test.js │ └── karma.test.js ├── e2e │ ├── seo.js │ ├── general.js │ └── admin.js └── globals.js ├── .travis.yml ├── LICENSE.md ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── CONTRIBUTING.md ├── nightwatch.json ├── server.socketio.js ├── Dockerfile └── .gitignore /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start -------------------------------------------------------------------------------- /scripts/start-mongod.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mongod --rest #--dbpath -------------------------------------------------------------------------------- /client/images/mean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/mean.png -------------------------------------------------------------------------------- /client/images/agenda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/agenda.png -------------------------------------------------------------------------------- /client/images/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/nodejs.png -------------------------------------------------------------------------------- /client/images/plato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/plato.png -------------------------------------------------------------------------------- /client/images/angularjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/angularjs.png -------------------------------------------------------------------------------- /client/images/expressjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/expressjs.png -------------------------------------------------------------------------------- /client/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/favicon.ico -------------------------------------------------------------------------------- /client/images/logo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/icon.png -------------------------------------------------------------------------------- /client/images/mongodb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/mongodb.png -------------------------------------------------------------------------------- /client/images/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/swagger.png -------------------------------------------------------------------------------- /client/modules/blog/blog.style.css: -------------------------------------------------------------------------------- 1 | /* 2 | normal .css files are supported and will be agregated with other styles. 3 | */ -------------------------------------------------------------------------------- /client/images/logo/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/header.png -------------------------------------------------------------------------------- /client/images/logo/icon2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/icon2x.png -------------------------------------------------------------------------------- /client/images/logo/icon3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/icon3x.png -------------------------------------------------------------------------------- /client/images/nightwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/nightwatch.png -------------------------------------------------------------------------------- /client/images/404pinkybrain.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/404pinkybrain.gif -------------------------------------------------------------------------------- /client/images/greenpioneer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/greenpioneer.png -------------------------------------------------------------------------------- /client/images/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/favicon.ico -------------------------------------------------------------------------------- /client/images/logo/header2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/header2x.png -------------------------------------------------------------------------------- /client/images/logo/header3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/header3x.png -------------------------------------------------------------------------------- /client/images/logo/iconword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/iconword.png -------------------------------------------------------------------------------- /client/images/mongoexpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/mongoexpress.png -------------------------------------------------------------------------------- /client/modules/admin/admin.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.admin', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /client/modules/chat/chat.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.chat', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /client/modules/index/index.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.index', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /client/modules/user/user.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.user', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /commands/blank/client/module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.<%= name %>', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /client/images/logo/darkheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkheader.png -------------------------------------------------------------------------------- /client/images/logo/iconword2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/iconword2x.png -------------------------------------------------------------------------------- /client/images/logo/iconword3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/iconword3x.png -------------------------------------------------------------------------------- /client/modules/blog/blog.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular.module('app.blog', ['app.core']) 5 | })() 6 | -------------------------------------------------------------------------------- /commands/template/client/module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | angular.module('app.<%= name %>', ['app.core']) 4 | })() 5 | -------------------------------------------------------------------------------- /client/images/logo/darkheader2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkheader2x.png -------------------------------------------------------------------------------- /client/images/logo/darkheader3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkheader3x.png -------------------------------------------------------------------------------- /client/images/logo/darkiconword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkiconword.png -------------------------------------------------------------------------------- /client/modules/footer/footer.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular.module('app.footer', ['app.core']) 5 | })() 6 | -------------------------------------------------------------------------------- /client/modules/header/header.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular.module('app.header', ['app.core']) 5 | })() 6 | -------------------------------------------------------------------------------- /client/images/logo/darkiconword 2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkiconword 2x.png -------------------------------------------------------------------------------- /client/images/logo/darkiconword 3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/HEAD/client/images/logo/darkiconword 3x.png -------------------------------------------------------------------------------- /commands/blank/server/socket.js: -------------------------------------------------------------------------------- 1 | var <%= name %> = require('./<%= name %>.controller.js') 2 | 3 | module.exports = function (io, socket) { 4 | // Socket 5 | } -------------------------------------------------------------------------------- /documentation/_Footer.md: -------------------------------------------------------------------------------- 1 | Copyright © Green Pioneer Solutions, LLC 2014 -2018 2 | ![Mean Stack JS](http://greenpioneersolutions.com/img/mean/header.png) 3 | 4 | -------------------------------------------------------------------------------- /commands/blank/server/spec.js: -------------------------------------------------------------------------------- 1 | // var assert = require('chai').assert 2 | // var request = require('supertest') 3 | 4 | // describe('<%= Name %>', function () { 5 | // }) 6 | -------------------------------------------------------------------------------- /commands/blank/server/controller.js: -------------------------------------------------------------------------------- 1 | exports.get<%= Name %> = get<%= Name %> 2 | 3 | function get<%= Name %>(req, res, next) { 4 | return res.status(200).send('<%= name %>') 5 | } 6 | 7 | -------------------------------------------------------------------------------- /server/modules/chat/chat.controller.js: -------------------------------------------------------------------------------- 1 | exports.onMessage = onMessage 2 | 3 | function onMessage (io, socket) { 4 | return function (msg) { 5 | io.emit('message', msg) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/modules/chat/chat.socket.js: -------------------------------------------------------------------------------- 1 | var chat = require('./chat.controller.js') 2 | 3 | module.exports = function (io, socket) { 4 | socket.on('message', chat.onMessage(io, socket)) 5 | } 6 | -------------------------------------------------------------------------------- /.nodemonignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.git/* 3 | /node_modules/* 4 | npm-debug.log 5 | /tests/* 6 | /commands/* 7 | /reports/* 8 | /client/* 9 | /documentation/* 10 | /database/* 11 | /scripts/* 12 | /tools/* -------------------------------------------------------------------------------- /commands/blank/client/spec.js: -------------------------------------------------------------------------------- 1 | describe('Generated <%= Name %> Testing', function () { 2 | beforeEach(module('app.<%= name %>')) 3 | beforeEach(module('app.core')) 4 | beforeEach(module('app.user')) 5 | }) 6 | -------------------------------------------------------------------------------- /commands/template/server/socket.js: -------------------------------------------------------------------------------- 1 | var <%= name %> = require('./<%= name %>.controller.js') 2 | 3 | module.exports = function (io, socket) { 4 | socket.on('<%= name %>', <%= name %>.on<%= Name %>(io, socket)) 5 | } -------------------------------------------------------------------------------- /commands/blank/client/view.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

View <%= Name %>

5 |
6 |
7 |
8 | -------------------------------------------------------------------------------- /commands/blank/server/model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | var <%= name %>Schema = mongoose.Schema({ 4 | <%= name %>: { 5 | type: String 6 | } 7 | }) 8 | 9 | module.exports = <%= name %>Schema 10 | -------------------------------------------------------------------------------- /commands/blank/server/routes.js: -------------------------------------------------------------------------------- 1 | var <%= name %> = require('./<%= name %>.controller.js') 2 | 3 | module.exports = function (app, auth, mail, settings, models) { 4 | // GET 5 | app.get('/api/<%= name %>/', <%= name %>.get<%= Name %>) 6 | } 7 | -------------------------------------------------------------------------------- /server/modules/system/setting.view.pug: -------------------------------------------------------------------------------- 1 | head 2 | title MEANSTACKJS Settings 3 | 4 | body 5 | ul 6 | each val,index in settings 7 | li= index +':'+ JSON.stringify(val) 8 | #footer 9 | p Copyright (c) MEANSTACKJS 10 | -------------------------------------------------------------------------------- /client/modules/core/core.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | 7 | -------------------------------------------------------------------------------- /commands/blank/client/style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Styles here should be specific to this module. It will be aggregated and compiled when the environment starts up. 3 | example code below 4 | ----------------------------- 5 | Generated by MEAN STACK JS - <%= name %> 6 | */ 7 | -------------------------------------------------------------------------------- /client/modules/index/index.style.less: -------------------------------------------------------------------------------- 1 | /* 2 | Less files are supported. They will be compiled and agregated with other styles. 3 | You can use less files. We just prefer to use .scss files for styling. 4 | example code below 5 | ----------------------------- 6 | */ 7 | 8 | -------------------------------------------------------------------------------- /scripts/generate-a11y-report.js: -------------------------------------------------------------------------------- 1 | const a11y = require('a11y') 2 | 3 | const options = { 4 | // viewportSize: '800x600', 5 | // delay:5, 6 | verbose: true 7 | } 8 | 9 | a11y('http://localhost:3000/', options, (err, reports) => { 10 | if (err)console.log(err) 11 | console.log(reports) 12 | }) 13 | -------------------------------------------------------------------------------- /client/modules/core/debug.view.html: -------------------------------------------------------------------------------- 1 |
2 |

Browser Debug Information

3 |

Please copy and paste this information below. Email it to Your Domain Admin

4 |
{{vm.browserInfo.giveMeAllYouGot()|json}}
5 |
-------------------------------------------------------------------------------- /client/modules/client.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular.module('app', [ 5 | 'app.core', 6 | 'app.index', 7 | 'app.header', 8 | 'app.footer', 9 | 'app.user', 10 | 'app.blog', 11 | 'app.admin', 12 | 'app.chat' // DONT REMOVE - APP GENERATOR 13 | ]) 14 | })() 15 | -------------------------------------------------------------------------------- /client/modules/footer/footer.style.scss: -------------------------------------------------------------------------------- 1 | /* Footer Styling */ 2 | 3 | footer{ 4 | margin-bottom: 25px; 5 | a{ 6 | margin-right: 15px; 7 | &:hover, &:focus{ 8 | text-decoration: none; 9 | } 10 | } 11 | 12 | i{ 13 | margin-right: 15px; 14 | 15 | &:before{ 16 | font-size: 20px; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/headers.js: -------------------------------------------------------------------------------- 1 | module.exports.headersMiddleware = headers 2 | 3 | function headers (self) { 4 | self.app.use(function (req, res, next) { 5 | // Add all custom system headers here 6 | // Force IE to use latest rendering engine or Chrome Frame 7 | res.header('X-UA-Compatible', 'IE=Edge,chrome=1') 8 | next() 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /commands/blank/client/factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>') 6 | .factory('<%= Name %>Factory', <%= Name %>Factory) 7 | 8 | <%= Name %>Factory.$inject = [] 9 | /* @ngInject */ 10 | function <%= Name %>Factory () { 11 | var self = this 12 | return self 13 | } 14 | }()) 15 | -------------------------------------------------------------------------------- /client/modules/footer/footer.view.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /server/modules/system/system.routes.js: -------------------------------------------------------------------------------- 1 | var system = require('./system.controller.js') 2 | 3 | module.exports = function (app, auth, mail, settings, models, logger) { 4 | app.get('/api/testing/', system.testing(mail, settings)) 5 | app.get('/api/settings/', system.pug(settings)) 6 | app.get('/api/system/status', system.status) 7 | app.use('/api/proxy/*', system.proxy) 8 | } 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Mean = require('./server.mean.js') 2 | var SocketIO = require('./server.socketio.js') 3 | var run = require('./run.js') 4 | var environment = require('./configs/environment.js').get() 5 | 6 | if (!module.parent) { 7 | if (environment === 'development') { 8 | run(Mean) 9 | run(SocketIO) 10 | } else { 11 | run(Mean) 12 | run(SocketIO) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /configs/environment.js: -------------------------------------------------------------------------------- 1 | var debug = require('debug')('meanstackjs:environment') 2 | var environment = process.env.NODE_ENV || 'development' 3 | 4 | exports.get = function (env) { 5 | environment = env || environment 6 | debug('get:', environment) 7 | return environment 8 | } 9 | exports.set = function (env) { 10 | environment = env 11 | debug('set:', environment) 12 | return environment 13 | } 14 | -------------------------------------------------------------------------------- /server/modules/admin/error.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | var errorSchema = mongoose.Schema({ 4 | timestamp: { 5 | type: Date, 6 | default: Date.now 7 | }, 8 | level: { 9 | type: String, 10 | default: 'error' 11 | }, 12 | message: { 13 | type: String, 14 | default: 'No message' 15 | }, 16 | meta: {} 17 | }) 18 | 19 | module.exports = errorSchema 20 | -------------------------------------------------------------------------------- /client/modules/core/core.module.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core', [ 6 | 'ngAnimate', 7 | 'ngSanitize', 8 | 'ngResource', 9 | 'ngCookies', 10 | 'ui.bootstrap', 11 | 'ui.router', 12 | 'angularMoment', 13 | 'ngFileUpload', 14 | 'angular-jwt', 15 | 'ngAria', 16 | 'ngMessages' 17 | ]) 18 | })() 19 | -------------------------------------------------------------------------------- /scripts/generate-development-doc.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var glob = require('glob') 3 | var files = glob.sync('./server/**/*.js') 4 | var documentation = require('documentation') 5 | files.unshift('./server.mean.js') 6 | documentation.build(['./server.mean.js'], {}) 7 | .then(documentation.formats.md) 8 | .then(res => { 9 | fs.writeFileSync('./documentation/Development-Document.md', res) 10 | }) 11 | -------------------------------------------------------------------------------- /tools/mongo_express/index.js: -------------------------------------------------------------------------------- 1 | module.exports = setupToolNightwatch 2 | 3 | var debug = require('debug')('meanstackjs:tools') 4 | 5 | function setupToolNightwatch (self) { 6 | debug('started setupToolNightwatch') 7 | if (self.environment === 'development') { 8 | var MongoExpress = require('./server.mongo_express.js') 9 | self.run(MongoExpress, self) 10 | } 11 | debug('end setupToolNightwatch') 12 | } 13 | -------------------------------------------------------------------------------- /documentation/Servers.md: -------------------------------------------------------------------------------- 1 | ### Servers 2 | 3 | #### server.mean.js 4 | 5 | Purpose: This is the main server file that runs our entire backend logic our of the server folder 6 | 7 | #### server.socketio.js 8 | 9 | Purpose: This is the socketio server file that aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms. 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tools/swagger/modules/users/models.js: -------------------------------------------------------------------------------- 1 | exports.models = { 2 | User: { 3 | id: 'User', 4 | required: ['email', 'password'], 5 | properties: { 6 | email: { 7 | type: 'string', 8 | description: 'Email used for authentication and notifications' 9 | }, 10 | password: { 11 | type: 'string', 12 | description: 'Password of the user' 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/modules/blog/blog.factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.blog') 6 | .factory('BlogFactory', BlogFactory) 7 | 8 | BlogFactory.$inject = ['$resource'] 9 | /* @ngInject */ 10 | function BlogFactory ($resource) { 11 | return $resource('/api/blog/:id', { 12 | id: '@id' 13 | }, { 14 | update: { 15 | method: 'PUT' 16 | } 17 | }) 18 | } 19 | }()) 20 | -------------------------------------------------------------------------------- /client/modules/core/core.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core') 6 | .controller('CoreController', LayoutController) 7 | 8 | LayoutController.$inject = ['config', 'logger'] 9 | /* @ngInject */ 10 | function LayoutController (config, logger) { 11 | var vm = this 12 | vm.message = 'layout' 13 | activate() 14 | 15 | function activate () { 16 | } 17 | } 18 | })() 19 | -------------------------------------------------------------------------------- /client/modules/footer/footer.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.footer') 6 | .controller('FooterController', FooterController) 7 | 8 | FooterController.$inject = ['config', 'logger'] 9 | /* @ngInject */ 10 | function FooterController (config, logger) { 11 | var vm = this 12 | vm.message = 'footer' 13 | activate() 14 | 15 | function activate () { 16 | } 17 | } 18 | })() 19 | -------------------------------------------------------------------------------- /tools/nightwatch/index.js: -------------------------------------------------------------------------------- 1 | module.exports = setupToolNightwatch 2 | 3 | var express = require('express') 4 | var debug = require('debug')('meanstackjs:tools') 5 | var path = require('path') 6 | 7 | function setupToolNightwatch (self) { 8 | debug('started setupToolNightwatch') 9 | if (self.environment === 'development') self.app.use('/e2e', express.static(path.join(self.dir, 'tools/nightwatch/reports'))) 10 | debug('end setupToolNightwatch') 11 | } 12 | -------------------------------------------------------------------------------- /commands/template/server/model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | var <%= name %>Schema = mongoose.Schema({ 4 | created: { 5 | type: Date, 6 | default: Date.now 7 | }, 8 | title: { 9 | type: String, 10 | trim: true 11 | }, 12 | content: { 13 | type: String, 14 | trim: true 15 | }, 16 | user: { 17 | type: mongoose.Schema.ObjectId, 18 | ref: 'users' 19 | } 20 | }) 21 | 22 | module.exports = <%= name %>Schema 23 | -------------------------------------------------------------------------------- /client/modules/admin/admin.style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Styles here should be specific to this module. It will be aggregated and compiled when the environment starts up. 3 | example code below 4 | ----------------------------- 5 | Generated by MEAN STACK JS - admin 6 | */ 7 | @import 'global-variables.styles.scss'; 8 | 9 | .admin-main{ 10 | max-width: 70rem; 11 | padding-left: 1rem; 12 | padding-right: 1rem; 13 | } 14 | 15 | .admin-post-meta{ 16 | color:$gray-light; 17 | } 18 | -------------------------------------------------------------------------------- /client/modules/index/index.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.index', []) 6 | .controller('IndexController', IndexController) 7 | 8 | IndexController.$inject = ['logger'] 9 | /* @ngInject */ 10 | function IndexController (logger) { 11 | var vm = this 12 | vm.title = 'System' 13 | 14 | activate() 15 | 16 | function activate () { 17 | logger.info('Activated Index View') 18 | } 19 | } 20 | })() 21 | -------------------------------------------------------------------------------- /commands/template/client/factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>') 6 | .factory('<%= Name %>Factory', <%= Name %>Factory) 7 | 8 | <%= Name %>Factory.$inject = ['$resource'] 9 | /* @ngInject */ 10 | function <%= Name %>Factory ($resource) { 11 | return $resource('/api/<%= name %>/:id', { 12 | id: '@id' 13 | }, { 14 | update: { 15 | method: 'PUT' 16 | } 17 | }) 18 | } 19 | }()) 20 | -------------------------------------------------------------------------------- /commands/template/client/style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Styles here should be specific to this module. It will be aggregated and compiled when the environment starts up. 3 | example code below 4 | ----------------------------- 5 | Generated by MEAN STACK JS - <%= name %> 6 | */ 7 | @import 'global-variables.styles.scss'; 8 | 9 | .<%= name %>-main{ 10 | max-width: 70rem; 11 | padding-left: 1rem; 12 | padding-right: 1rem; 13 | } 14 | 15 | .<%= name %>-post-meta{ 16 | color:$gray-light; 17 | } 18 | -------------------------------------------------------------------------------- /server/tools.js: -------------------------------------------------------------------------------- 1 | module.exports.setupTools = tools 2 | 3 | var _ = require('lodash') 4 | var glob = require('glob') 5 | 6 | function tools (self) { 7 | var files = glob.sync('./tools/*/package.json') 8 | files.forEach(function (n, k) { 9 | var packageInfo = require('../' + n) 10 | if (packageInfo.active || _.isUndefined(packageInfo.active)) { 11 | var mainPath = _.replace(n, 'package.json', packageInfo.main) 12 | require('../' + mainPath)(self) 13 | } 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /tools/swagger/modules/blogs/services.js: -------------------------------------------------------------------------------- 1 | exports.load = function (swagger, parms) { 2 | var searchParms = parms.searchableOptions 3 | var Bloglist = { 4 | 'spec': { 5 | description: 'Blog operations', 6 | path: '/blog', 7 | method: 'GET', 8 | summary: 'Get Blog', 9 | notes: '', 10 | type: 'Blog', 11 | nickname: 'getBlog', 12 | produces: ['application/json'], 13 | parameters: searchParms 14 | } 15 | } 16 | 17 | swagger.addGet(Bloglist) 18 | } 19 | -------------------------------------------------------------------------------- /client/styles/global.style.scss: -------------------------------------------------------------------------------- 1 | /* global styling */ 2 | /* import css framework first - bootstrap example*/ 3 | /*@import 'foundation';*/ 4 | /*@import 'materialize';*/ 5 | @import 'global-variables.styles.scss';/* copy of bootstrap variables for custom theme*/ 6 | @import 'bootstrap';/*importing bootstrap scss files */ 7 | @import 'font-awesome'; 8 | 9 | body{ 10 | padding-top:50px; 11 | } 12 | 13 | h1{ 14 | color:$brand-primary; 15 | } 16 | 17 | .center-col { 18 | float: none; 19 | margin: 0 auto; 20 | } 21 | -------------------------------------------------------------------------------- /tests/unit/mocha.test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'nightwatch' 2 | var Mean = require('../../server.mean.js') 3 | var run = require('../../run.js') 4 | describe('MEANSTACKJS API Testing', function () { 5 | before(function (done) { 6 | this.timeout(20000) 7 | run(Mean, function () { 8 | require('../seed.js')(function () { 9 | done() 10 | }) 11 | }) 12 | }) 13 | require('glob').sync('server/modules/**/*.spec.js').forEach(function (file) { 14 | require('../../' + file) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /server/modules/blog/blog.model.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | 3 | var blogSchema = mongoose.Schema({ 4 | created: { 5 | type: Date, 6 | default: Date.now 7 | }, 8 | title: { 9 | type: String, 10 | trim: true, 11 | required: true 12 | }, 13 | content: { 14 | type: String, 15 | trim: true, 16 | required: true 17 | }, 18 | user: { 19 | type: mongoose.Schema.ObjectId, 20 | ref: 'users', 21 | required: true 22 | } 23 | }) 24 | 25 | module.exports = blogSchema 26 | -------------------------------------------------------------------------------- /server/modules/system/system.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var request = require('supertest') 3 | 4 | describe('SYSTEM', function () { 5 | describe('GET /api/testing', function () { 6 | it('should be returning object', function (done) { 7 | request('localhost:3000/') 8 | .get('api/testing') 9 | .expect(200, function (error, res) { 10 | if (error) return done(error) 11 | assert.isObject(res.body.query) 12 | done() 13 | }) 14 | }) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /commands/template/server/spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var request = require('supertest') 3 | 4 | describe('<%= Name %>', function () { 5 | describe('GET /api/<%= name %>', function () { 6 | it('should be returning <%= name %>', function (done) { 7 | request('localhost:3000/') 8 | .get('api/<%= name %>') 9 | .expect(200, function (error, res) { 10 | if (error) return done(error) 11 | assert.deepEqual(res.body, []) 12 | done() 13 | }) 14 | }) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /client/modules/admin/log.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Logs

6 |
7 |
8 |
9 |

{{key}}

10 |
{{message|json}}
11 |
12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /tools/nightwatch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-nightwatch", 3 | "version": "1.0.0", 4 | "description": "Used to set up the view into the reporting of how e2e did . http://localhost:3000/e2e/", 5 | "main": "index.js", 6 | "active": true, 7 | "author": "Green Pioneer ", 8 | "license": "MIT", 9 | "dependencies": { 10 | "express": "4.14.0" 11 | }, 12 | "devDependencies": {}, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/plato/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-plato", 3 | "version": "1.0.0", 4 | "description": "Used to set up the view into the reporting of how the analysis . http://localhost:3000/plato/", 5 | "main": "index.js", 6 | "author": "Green Pioneer ", 7 | "license": "MIT", 8 | "dependencies": { 9 | "express": "4.14.0", 10 | "plato": "1.5.0" 11 | }, 12 | "devDependencies": {}, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/swagger/modules/blogs/models.js: -------------------------------------------------------------------------------- 1 | exports.models = { 2 | Blog: { 3 | id: 'Blog', 4 | required: [], 5 | properties: { 6 | created: { 7 | type: 'date', 8 | description: 'created of the blog' 9 | }, 10 | title: { 11 | type: 'string', 12 | description: 'title of the blog' 13 | }, 14 | content: { 15 | type: 'string', 16 | description: 'content of the blog' 17 | }, 18 | user: { 19 | type: 'string', 20 | description: 'Ref to the user' 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /client/modules/blog/blog.style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Styles here should be specific to this module. It will be aggregated and compiled when the environment starts up. 3 | example code below 4 | ----------------------------- 5 | */ 6 | @import 'global-variables.styles.scss'; 7 | 8 | .blog-main{ 9 | max-width: 100rem; 10 | padding-left: 1rem; 11 | padding-right: 1rem; 12 | } 13 | 14 | .blog-post{ 15 | border-bottom: 1px solid #ddd; 16 | max-width: 100rem; 17 | padding-bottom: 3rem; 18 | &:last-child { 19 | border-bottom: none; 20 | } 21 | } 22 | 23 | .blog-post-meta{ 24 | color:$gray-light; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /server/modules/blog/blog.routes.js: -------------------------------------------------------------------------------- 1 | var blog = require('./blog.controller.js') 2 | 3 | module.exports = function (app, auth, mail, settings, models, logger) { 4 | // GET 5 | app.get('/api/blog/', blog.getBlog) 6 | app.get('/api/blog/:blogId', blog.getBlogById) 7 | 8 | // POST 9 | app.post('/api/blog', auth.isAuthenticated, blog.postBlog) 10 | 11 | // PUT 12 | app.put('/api/blog/:blogId', auth.isAuthorized('blog'), blog.putBlog) 13 | 14 | // DELETE 15 | app.delete('/api/blog/:blogId', auth.isAuthorized('blog'), blog.deleteBlog) 16 | 17 | // PARAM 18 | app.param('blogId', blog.paramBlog) 19 | } 20 | -------------------------------------------------------------------------------- /scripts/postinstall.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var path = require('path') 3 | var shell = require('shelljs') 4 | var toolsDir = path.join(process.cwd(), 'tools') 5 | fs.readdir(toolsDir, function (err, files) { 6 | console.log('Start Tools Install') 7 | if (err && err.code !== 'ENOENT') throw Error(err) 8 | if (!files || !files.length) return 9 | files.forEach(function (file, key) { 10 | if (file === '.DS_Store') return 11 | shell.cd(toolsDir + '/' + file) 12 | shell.exec('npm install', { silent: false }, function () { 13 | console.log('Finished Installing ' + file) 14 | }) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /client/modules/core/util.config.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | var util = angular.module('app.core') 5 | util.config(interceptors) 6 | 7 | interceptors.$inject = ['$httpProvider', 'jwtInterceptorProvider'] 8 | /* @ngInject */ 9 | function interceptors ($httpProvider, jwtInterceptorProvider) { 10 | jwtInterceptorProvider.tokenGetter = function () { 11 | return localStorage.getItem('JWT') 12 | } 13 | 14 | $httpProvider.interceptors.push('jwtInterceptor') 15 | $httpProvider.interceptors.push('httpInterceptor') 16 | $httpProvider.interceptors.push('noCacheInterceptor') 17 | } 18 | })() 19 | -------------------------------------------------------------------------------- /client/modules/chat/chat.routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.chat') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: 'chat', 18 | config: { 19 | url: '/chat', 20 | templateUrl: 'modules/chat/chat.view.html', 21 | controller: 'ChatController', 22 | controllerAs: 'vm' 23 | } 24 | } 25 | ] 26 | } 27 | })() 28 | -------------------------------------------------------------------------------- /commands/blank/client/controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>', []) 6 | .controller('<%= Name %>Controller', <%= Name %>Controller) 7 | 8 | <%= Name %>Controller.$inject = ['$http', '$stateParams', '<%= Name %>Factory', 'logger', '$location', 'UserFactory'] 9 | /* @ngInject */ 10 | function <%= Name %>Controller ($http, $stateParams, <%= Name %>Factory, logger, $location, UserFactory) { 11 | var vm = this 12 | vm.<%= name %> = {} 13 | vm.UserFactory = UserFactory 14 | activate() 15 | 16 | function activate () { 17 | 18 | } 19 | } 20 | })() 21 | -------------------------------------------------------------------------------- /client/modules/index/index.routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.index') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: 'index', 18 | config: { 19 | url: '/', 20 | templateUrl: 'modules/index/index.view.html', 21 | controller: 'IndexController', 22 | controllerAs: 'vm' 23 | } 24 | } 25 | ] 26 | } 27 | })() 28 | -------------------------------------------------------------------------------- /scripts/nodejs-change-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # if you need more help installing node - https://gist.github.com/isaacs/579814 3 | # 4 | 5 | [ $(node -p process.platform) == "win32" ] && echo "Please Update Node.js from https://nodejs.org and install it." && exit 1 6 | 7 | export NVM_DIR="$HOME/.nvm" 8 | [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm 9 | 10 | if [ $(type -t nvm) == "function" ]; then 11 | echo "Successfully loaded nvm." 12 | else 13 | echo "Please install nvm and try again." 14 | exit 1 15 | fi 16 | 17 | echo "Please enter a version of Node.js" 18 | read input_variable 19 | nvm install $input_variable 20 | -------------------------------------------------------------------------------- /server/mail.js: -------------------------------------------------------------------------------- 1 | exports.send = send 2 | 3 | var nodemailer = require('nodemailer') 4 | var settings = require('../configs/settings.js').get() 5 | var debug = require('debug')('meanstackjs:mail') 6 | var transporter = nodemailer.createTransport(settings.email.connect) 7 | 8 | function send (message, cb) { 9 | var mailOptions = { 10 | to: message.to, 11 | from: settings.email.from, 12 | subject: message.subject, 13 | text: message.text 14 | } 15 | 16 | debug('mailOptions', mailOptions) 17 | transporter.sendMail(mailOptions, function (error) { 18 | if (error) debug('mail error:', error) 19 | cb(error) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /tools/mongo_express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-mongo_express", 3 | "version": "1.0.0", 4 | "description": "Web-based MongoDB admin interface, written with Node.js and express. http://localhost:8081", 5 | "main": "index.js", 6 | "active": true, 7 | "author": "Green Pioneer ", 8 | "license": "MIT", 9 | "dependencies": { 10 | "express": "4.14.0", 11 | "mongo-express": "0.32.0", 12 | "mongodb-uri": "0.9.7" 13 | }, 14 | "devDependencies": {}, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/modules/core/core.directive.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core') 6 | .directive('ngEnter', ngEnter) 7 | 8 | function ngEnter () { 9 | return function (scope, element, attrs) { 10 | element.bind('keydown keypress', function (event) { 11 | if (event.which === 13) { 12 | setTimeout(function () { 13 | // added set time because of the digest loop 14 | scope.$apply(function () { 15 | scope.$eval(attrs.ngEnter) 16 | }) 17 | }) 18 | event.preventDefault() 19 | } 20 | }) 21 | } 22 | } 23 | })() 24 | -------------------------------------------------------------------------------- /tools/swagger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-swagger", 3 | "version": "1.0.0", 4 | "description": "Used to set up swagger.io to represent the api with a nice ui. http://localhost:3000/api/", 5 | "main": "index.js", 6 | "active": true, 7 | "author": "Green Pioneer ", 8 | "license": "MIT", 9 | "dependencies": { 10 | "express": "4.14.0", 11 | "lodash": "4.17.2", 12 | "swagger-node-express": "2.1.3", 13 | "swagger-ui": "2.1.8-M1" 14 | }, 15 | "devDependencies": {}, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /commands/blank/client/routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: '<%= name %>View', 18 | config: { 19 | url: '/<%= name %>/view', 20 | templateUrl: 'modules/<%= name %>/view.view.html', 21 | controller: '<%= Name %>Controller', 22 | controllerAs: 'vm' 23 | } 24 | } 25 | ] 26 | } 27 | })() 28 | -------------------------------------------------------------------------------- /commands/template/server/routes.js: -------------------------------------------------------------------------------- 1 | var <%= name %> = require('./<%= name %>.controller.js') 2 | 3 | module.exports = function (app, auth, mail, settings, models, logger) { 4 | // GET 5 | app.get('/api/<%= name %>/', <%= name %>.get<%= Name %>) 6 | app.get('/api/<%= name %>/:<%= name %>Id', <%= name %>.get<%= Name %>ById) 7 | // POST 8 | app.post('/api/<%= name %>', <%= name %>.post<%= Name %>) 9 | // PUT 10 | app.put('/api/<%= name %>/:<%= name %>Id', <%= name %>.put<%= Name %>) 11 | // DELETE 12 | app.delete('/api/<%= name %>/:<%= name %>Id', <%= name %>.delete<%= Name %>) 13 | // PARAM 14 | app.param('<%= name %>Id', <%= name %>.param<%= Name %>) 15 | } 16 | -------------------------------------------------------------------------------- /tools/agenda/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-agenda", 3 | "version": "1.0.0", 4 | "description": " Used to set up agenda to manage light-weight job scheduling with a nice ui. http://localhost:3000/agenda", 5 | "main": "index.js", 6 | "active": true, 7 | "author": "Green Pioneer ", 8 | "license": "MIT", 9 | "dependencies": { 10 | "agenda": "0.9.0", 11 | "agendash": "0.4.0", 12 | "mongodb-backup": "1.6.8", 13 | "mongodb-restore": "1.6.1" 14 | }, 15 | "devDependencies": {}, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/modules/chat/chat.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

MeanStackJS Chatroom

5 |
6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 |
14 |

{{chat.message}} - by {{chat.user}} on {{chat.date|date:'medium'}}

15 |
16 |
17 | -------------------------------------------------------------------------------- /client/modules/footer/footer.spec.js: -------------------------------------------------------------------------------- 1 | describe('FOOTER Testing', function () { 2 | describe('controller', function () { 3 | var FooterController 4 | beforeEach(module('app.footer')) 5 | beforeEach(inject(function ($controller, $rootScope) { 6 | var $scope = $rootScope.$new() 7 | FooterController = $controller('FooterController', { $scope: $scope }) 8 | })) 9 | 10 | it('should exist', function () { 11 | expect(FooterController).to.exist 12 | }) 13 | }) 14 | 15 | this.timeout(500) 16 | 17 | it('should take less than 500ms', function (done) { 18 | setTimeout(done, 300) 19 | }) 20 | 21 | it('should take less than 500ms as well', function (done) { 22 | setTimeout(done, 200) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /client/modules/blog/blog.style.less: -------------------------------------------------------------------------------- 1 | /* 2 | Less files are supported. They will be compiled and agregated with other styles. 3 | You can use less files. We just prefer to use .scss files for styling. 4 | example code below 5 | ----------------------------- 6 | @base: #f938ab; 7 | 8 | .box-shadow(@style, @c) when (iscolor(@c)) { 9 | -webkit-box-shadow: @style @c; 10 | box-shadow: @style @c; 11 | } 12 | .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { 13 | .box-shadow(@style, rgba(0, 0, 0, @alpha)); 14 | } 15 | .box { 16 | color: saturate(@base, 5%); 17 | border-color: lighten(@base, 30%); 18 | div { .box-shadow(0 0 5px, 30%) } 19 | } 20 | 21 | body{ 22 | background-color:@base; 23 | } 24 | 25 | */ 26 | 27 | -------------------------------------------------------------------------------- /client/modules/blog/view.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Blog Post View

5 |
6 |
7 |
8 |
9 |

{{vm.blog.title}}

10 | 11 | 12 | 13 |
{{vm.blog.content}}
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /tools/livereload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meanstackjs-livereload", 3 | "version": "1.0.0", 4 | "description": "Used to set up livereload which allows you as the developer to develop faster due to not having to manually restarting the server after every change", 5 | "main": "index.js", 6 | "active": true, 7 | "author": "Green Pioneer ", 8 | "license": "MIT", 9 | "dependencies": { 10 | "chalksay": "1.1.0", 11 | "chokidar": "1.6.1", 12 | "less": "2.7.1", 13 | "livereload": "0.6.0", 14 | "lodash": "4.17.2", 15 | "node-sass": "^4.5.0" 16 | }, 17 | "devDependencies": {}, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/greenpioneersolutions/meanstackjs.git" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/cdn.js: -------------------------------------------------------------------------------- 1 | module.exports.maxCDN = cdn 2 | 3 | var MaxCDN = require('maxcdn') 4 | 5 | function cdn (self) { 6 | if (self.settings.maxcdn.zoneId) { 7 | var maxcdn = new MaxCDN( 8 | self.settings.maxcdn.companyAlias, 9 | self.settings.maxcdn.consumerKey, 10 | self.settings.maxcdn.consumerSecret 11 | ) 12 | maxcdn.del('zones/pull.json/' + self.settings.maxcdn.zoneId + '/cache', function (error, res) { 13 | self.logger.info('MAXCDN: STATUS') 14 | if (error) { 15 | self.logger.warn('PURGE ERROR: ', error.stack || error.message || error) 16 | return 17 | } else if (res.code !== 200) { 18 | self.logger.warn('PURGE ERROR: ', res.code) 19 | return 20 | } 21 | self.logger.info('PURGE SUCCESS') 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/unset-proxies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -e "\033[1mTo Unset in windows - run these commands\033[0m" 3 | echo '' 4 | echo 'set https_proxy=""' 5 | echo 'set http_proxy=""' 6 | echo '' 7 | echo '' 8 | echo -e "\033[1mExport Proxies Unset linux,mac - run these commands\033[0m" 9 | echo '' 10 | echo 'export https_proxy=""' 11 | echo 'export http_proxy=""' 12 | echo 'unset https_proxy' 13 | echo 'unset http_proxy' 14 | echo '' 15 | echo '' 16 | echo -e "\033[1mUnset Git - run these commands\033[0m" 17 | echo '' 18 | echo 'git config --global --unset https.proxy ' 19 | echo 'git config --global --unset http.proxy ' 20 | echo '' 21 | echo '' 22 | echo -e "\033[1mUnset NPM - run these commands\033[0m" 23 | echo '' 24 | echo 'npm config rm proxy' 25 | echo 'npm config rm https-proxy' 26 | echo '' 27 | echo '' 28 | 29 | -------------------------------------------------------------------------------- /client/modules/admin/admin.routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.admin') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: 'adminDashboard', 18 | config: { 19 | url: '/admin?view', 20 | templateUrl: 'modules/admin/view.view.html', 21 | controller: 'AdminController', 22 | controllerAs: 'vm', 23 | resolve: { 24 | loggedin: function (UserFactory) { 25 | return UserFactory.checkAdmin() 26 | } 27 | } 28 | } 29 | } 30 | ] 31 | } 32 | })() 33 | -------------------------------------------------------------------------------- /commands/template/client/view.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

View <%= Name %>

5 |
6 |
7 |
8 |
9 |

{{vm.<%= name %>.title}}

10 | 11 | 12 | 13 |

{{vm.<%= name %>.content}}

14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /tools/livereload/server.livereload.js: -------------------------------------------------------------------------------- 1 | module.exports = Livereload 2 | 3 | var path = require('path') 4 | var livereload = require('livereload') 5 | var debug = require('debug')('meanstackjs:livereload') 6 | var fs = require('fs') 7 | 8 | function Livereload (self, done) { 9 | if(self.settings.https.active){ 10 | var serverHttps = livereload.createServer({ 11 | https:{ 12 | key: fs.readFileSync(self.settings.https.key), 13 | cert: fs.readFileSync(self.settings.https.cert) 14 | }, 15 | port:35730 16 | }) 17 | serverHttps.watch(path.join(__dirname, '../../client')) 18 | } 19 | if(self.settings.http.active){ 20 | var serverHttp = livereload.createServer({ 21 | port:35729 22 | }) 23 | serverHttp.watch(path.join(__dirname, '../../client')) 24 | } 25 | debug('starting Livereload Server') 26 | done(null) 27 | } 28 | -------------------------------------------------------------------------------- /client/modules/admin/admin.spec.js: -------------------------------------------------------------------------------- 1 | describe('Generated Admin Testing', function () { 2 | beforeEach(module('app.admin')) 3 | beforeEach(module('app.core')) 4 | beforeEach(module('app.user')) 5 | 6 | describe('routes', function () { 7 | var states = {} 8 | beforeEach(inject(function ($state) { 9 | states.view = $state.get('adminDashboard') 10 | })) 11 | describe('view', function () { 12 | it('should have the correct url', function () { 13 | expect(states.view.url).to.equal('/admin?view') 14 | }) 15 | 16 | it('should have the correct templateUrl', function () { 17 | expect(states.view.templateUrl).to.equal('modules/admin/view.view.html') 18 | }) 19 | 20 | it('should have the correct controller', function () { 21 | expect(states.view.controller).to.equal('AdminController') 22 | }) 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /server/modules/blog/blog.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var request = require('supertest') 3 | var blogid = '' 4 | 5 | describe('BLOG', function () { 6 | describe('GET /api/blog', function () { 7 | it('should be returning array', function (done) { 8 | request('localhost:3000/') 9 | .get('api/blog') 10 | .expect(200, function (error, res) { 11 | if (error) return done(error) 12 | assert.isArray(res.body.blogs) 13 | blogid = res.body.blogs[0]._id 14 | done() 15 | }) 16 | }) 17 | it('should be returning object', function (done) { 18 | request('localhost:3000/') 19 | .get('api/blog/' + blogid) 20 | .expect(200, function (error, res) { 21 | if (error) return done(error) 22 | assert.isObject(res.body) 23 | done() 24 | }) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /scripts/generate-changelog.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var request = require('request') 3 | var moment = require('moment') 4 | request.get({ 5 | url: 'https://api.github.com/repos/greenpioneersolutions/meanstackjs/releases?per_page=150', 6 | headers: { 7 | 'Content-Type': 'application/json', 8 | 'user-agent': 'changelog' 9 | } 10 | }, function (error, response, body) { 11 | if (error) throw new Error(error) 12 | var data = JSON.parse(body) 13 | var changelog = '### Changelog\n' 14 | 15 | for (var i = 0; i < data.length; i++) { 16 | changelog += '\n' 17 | changelog += '#### ' 18 | changelog += moment(data[i].published_at).format('MMM Do YY') 19 | changelog += ' - ' 20 | changelog += data[i].name 21 | changelog += '\n' 22 | changelog += data[i].body 23 | changelog += '\n' 24 | } 25 | fs.writeFileSync('./documentation/changelog.md', changelog) 26 | }) 27 | -------------------------------------------------------------------------------- /documentation/Tools.md: -------------------------------------------------------------------------------- 1 | ### Tools 2 | 3 | #### [Livereload](https://www.npmjs.com/package/livereload) 4 | 5 | #### [Mongo Express](https://www.npmjs.com/package/mongo-express) 6 | 7 | #### Agenda 8 | 9 | Agenda is a light-weight job scheduling library for Node.js. 10 | 11 | ![Auto-refresh list of jobs](https://github.com/greenpioneersolutions/meanstackjs/blob/master/client/images/agenda.png) 12 | 13 | #### Swagger 14 | 15 | Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API 16 | 17 | ![Auto-refresh list of jobs](https://github.com/greenpioneersolutions/meanstackjs/blob/master/client/images/swagger.png) 18 | 19 | #### Plato 20 | 21 | JavaScript source code visualization, static analysis, and complexity tool 22 | 23 | ![Auto-refresh list of jobs](https://github.com/greenpioneersolutions/meanstackjs/blob/master/client/images/plato.png) -------------------------------------------------------------------------------- /tools/plato/index.js: -------------------------------------------------------------------------------- 1 | module.exports = setupToolPlato 2 | 3 | var express = require('express') 4 | var debug = require('debug')('meanstackjs:tools') 5 | var plato = require('plato') 6 | var path = require('path') 7 | 8 | function setupToolPlato (self) { 9 | debug('started setupToolPlato') 10 | if (self.environment === 'development') { 11 | self.app.use('/plato', express.static(path.join(self.dir, 'tools/plato/reports/'))) 12 | var files = [ 13 | path.join(__dirname, '../../*.js'), 14 | path.join(__dirname, '../../client/*.js'), 15 | path.join(__dirname, '../../server/*.js') 16 | ] 17 | // FILES, REPORT DIR , OPTIONS, CALLBACK WITH REPORT 18 | plato.inspect(files, path.join(__dirname, './reports/'), self.settings.plato, function (report) { 19 | // console.log(report, 'report') 20 | // console.log(plato.getOverviewReport(report), 'getOverviewReport') 21 | }) 22 | } 23 | debug('end setupToolPlato') 24 | } 25 | -------------------------------------------------------------------------------- /client/modules/index/index.spec.js: -------------------------------------------------------------------------------- 1 | describe('INDEX Testing', function () { 2 | beforeEach(module('app')) 3 | 4 | describe('route', function () { 5 | var indexState 6 | beforeEach(inject(function ($state) { 7 | indexState = $state.get('index') 8 | })) 9 | 10 | it('should have the correct url', function () { 11 | expect(indexState.url).to.equal('/') 12 | }) 13 | 14 | it('should have the correct templateUrl', function () { 15 | expect(indexState.templateUrl).to.equal('modules/index/index.view.html') 16 | }) 17 | 18 | it('should have the correct controller', function () { 19 | expect(indexState.controller).to.equal('IndexController') 20 | }) 21 | }) 22 | 23 | this.timeout(500) 24 | 25 | it('should take less than 500ms', function (done) { 26 | setTimeout(done, 300) 27 | }) 28 | 29 | it('should take less than 500ms as well', function (done) { 30 | setTimeout(done, 200) 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /server/modules/admin/admin.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var request = require('supertest') 3 | 4 | describe('Admin', function () { 5 | describe('GET /api/admin/users', function () { 6 | it('should be returning no users - unauthorized', function (done) { 7 | request('localhost:3000/') 8 | .get('api/admin/users') 9 | .expect(401, function (error, res) { 10 | if (error) return done(error) 11 | assert.equal(res.body.success, false) 12 | done() 13 | }) 14 | }) 15 | }) 16 | describe('GET /api/admin/users', function () { 17 | it('should be returning no errors - unauthorized', function (done) { 18 | request('localhost:3000/') 19 | .get('api/admin/errors') 20 | .expect(401, function (error, res) { 21 | if (error) return done(error) 22 | assert.equal(res.body.success, false) 23 | done() 24 | }) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /server/modules/users/users.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert 2 | var request = require('supertest') 3 | 4 | describe('USERS', function () { 5 | describe('GET /api/user', function () { 6 | it('should be returning unauthenticated', function (done) { 7 | request('localhost:3000/') 8 | .get('api/user/authenticate') 9 | .expect(200, function (error, res) { 10 | if (error) return done(error) 11 | assert.equal(res.body.success, false) 12 | assert.equal(res.body.authenticated, false) 13 | assert.equal(res.body.redirect, false) 14 | done() 15 | }) 16 | }) 17 | it('should be returning token', function (done) { 18 | request('localhost:3000/') 19 | .get('api/user/token') 20 | .expect(401, function (error, res) { 21 | if (error) return done(error) 22 | assert.equal(res.body.success, false) 23 | done() 24 | }) 25 | }) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /scripts/set-proxies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo -e "\033[1mTo set proxies please enter your proxy in EX. http://proxy.greenpioneersolutions.com:8080\033[0m" 3 | echo -e "\033[1mExport Proxies Set in windows - run these commands\033[0m" 4 | echo '' 5 | echo 'set https_proxy="" ' 6 | echo 'set http_proxy=""' 7 | echo '' 8 | echo '' 9 | echo -e "\033[1mExport Proxies Set in linux,mac - run these commands\033[0m" 10 | echo '' 11 | echo 'export https_proxy="" ' 12 | echo 'export http_proxy=""' 13 | echo '' 14 | echo '' 15 | echo -e "\033[1mGit Proxies Set- run these commands\033[0m" 16 | echo '' 17 | echo 'git config --global https.proxy ""' 18 | echo 'git config --global http.proxy ""' 19 | echo '' 20 | echo '' 21 | echo -e "\033[1mNPM Proxy Set- run these commands\033[0m" 22 | echo '' 23 | echo 'npm config set proxy ""' 24 | echo 'npm config set https-proxy ""' 25 | echo '' 26 | echo '' 27 | -------------------------------------------------------------------------------- /scripts/update-meanstackjs.js: -------------------------------------------------------------------------------- 1 | var request = require('request') 2 | var semver = require('semver') 3 | var spawn = require('child_process').spawn 4 | request({ 5 | json: true, 6 | url: 'https://raw.githubusercontent.com/greenpioneersolutions/meanstackjs/master/package.json' 7 | }, function (err, res, body) { 8 | if (err) return console.log('Error:', err) 9 | var current = require('../package.json').version 10 | var next = body.version 11 | if (next === current) { 12 | console.log('You are up-to-date.') 13 | return 14 | } 15 | if (semver.major(next) > semver.major(current)) { 16 | console.log('You are going to update to a major release which may contain breaking changes.') 17 | console.log('Please run `git merge --abort` if you want to cancel the process.') 18 | } 19 | console.log('This will update from GitHub the latest changes. Conflicts may appear.') 20 | spawn('git', ['pull', 'https://github.com/greenpioneersolutions/meanstackjs', 'master'], { 21 | stdio: 'inherit' 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /client/modules/core/storage.factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core') 6 | .factory('$localStorage', localStorage) 7 | 8 | localStorage.$inject = ['$window'] 9 | 10 | function localStorage ($window) { 11 | return { 12 | set: function (key, value) { 13 | $window.localStorage[key] = value 14 | }, 15 | get: function (key, defaultValue) { 16 | return $window.localStorage[key] || false 17 | }, 18 | setObject: function (key, value) { 19 | $window.localStorage[key] = JSON.stringify(value) 20 | }, 21 | getObject: function (key) { 22 | if ($window.localStorage[key] !== undefined) { 23 | return JSON.parse($window.localStorage[key] || false) 24 | } 25 | return false 26 | }, 27 | remove: function (key) { 28 | $window.localStorage.removeItem(key) 29 | }, 30 | clear: function () { 31 | $window.localStorage.clear() 32 | } 33 | } 34 | } 35 | }()) 36 | -------------------------------------------------------------------------------- /scripts/generate-ssl-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -e index.js ] 4 | then 5 | echo "Please run the generate-ssl-certs.sh script from the main root directory" 6 | echo "i.e: bash scripts/generate-ssl-certs.sh" 7 | echo "Or by npm run generate-ssl-certs" 8 | exit -1 9 | fi 10 | 11 | echo "Generating self-signed certificates..." 12 | 13 | mkdir -p ./configs/certificates 14 | openssl req -x509 -newkey rsa:2048 -keyout ./configs/certificates/key.pem -out ./configs/certificates/cert.pem -days 365 15 | openssl rsa -in ./configs/certificates/key.pem -out ./configs/certificates/newkey.pem && mv ./configs/certificates/newkey.pem ./configs/certificates/key.pem 16 | 17 | if [ ! -e ./configs/certificates/key.pem ] 18 | then 19 | echo "Error has occured creating the key.pem" 20 | exit -1 21 | fi 22 | 23 | if [ ! -e ./configs/certificates/cert.pem ] 24 | then 25 | echo "Error has occured creating the cert.pem" 26 | exit -1 27 | fi 28 | 29 | echo "Generated self-signed certificates at ./configs/certificates/key.pem & ./configs/certificates/cert.pem" -------------------------------------------------------------------------------- /client/modules/core/core.config.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | var core = angular.module('app.core') 5 | 6 | core.config(toastrConfig) 7 | core.constant('toastr', toastr) 8 | core.constant('moment', moment) 9 | core.constant('_', _) 10 | toastrConfig.$inject = ['toastr'] 11 | /* @ngInject */ 12 | function toastrConfig (toastr) { 13 | toastr.options.timeOut = 4000 14 | toastr.options.positionClass = 'toast-bottom-right' 15 | } 16 | 17 | /* $window change out */ 18 | var config = { 19 | appErrorPrefix: window.name, 20 | appTitle: window.name 21 | } 22 | core.value('config', config) 23 | 24 | core.config(configure) 25 | 26 | configure.$inject = ['$logProvider', 'routerHelperProvider', 'exceptionHandlerProvider'] 27 | /* @ngInject */ 28 | function configure ($logProvider, routerHelperProvider, exceptionHandlerProvider) { 29 | if ($logProvider.debugEnabled) { 30 | $logProvider.debugEnabled(true) 31 | } 32 | exceptionHandlerProvider.configure(config.appErrorPrefix) 33 | } 34 | })() 35 | -------------------------------------------------------------------------------- /scripts/mongodb-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # if you need more help installing mongodb - https://docs.mongodb.com/manual/administration/install-community/ 3 | # 4 | 5 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then 6 | echo "Please follow this page to install MongoDB: https://docs.mongodb.com/manual/administration/install-community" 7 | exit 1 8 | fi 9 | 10 | 11 | CURRENT=`pwd` 12 | DOWNLOADSDIR="$CURRENT/downloads/mongodb-linux-x86_64-3.4.1.tgz" 13 | EXPORTPATH="$CURRENT/database/mongodb/bin" 14 | 15 | if [ ! -e index.js ] 16 | then 17 | echo "Please run the mongodb-install.sh script from the main root directory" 18 | echo "i.e: bash scripts/mongodb-install.sh" 19 | echo "Or by npm run mongodb-install" 20 | exit -1 21 | fi 22 | mkdir -p ./downloads ./database/mongodb/db 23 | cd ./downloads 24 | curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.1.tgz 25 | cd ../database 26 | tar -zxvf "$DOWNLOADSDIR" 27 | cp -R -n mongodb-linux-x86_64-3.4.1/ mongodb 28 | rm -rf ./mongodb-linux-x86_64-3.4.1 29 | export PATH="$EXPORTPATH":$PATH 30 | -------------------------------------------------------------------------------- /tools/swagger/modules/users/services.js: -------------------------------------------------------------------------------- 1 | exports.load = function (swagger, parms) { 2 | var searchParms = parms.searchableOptions 3 | var list = { 4 | 'spec': { 5 | description: 'Authenticate operations', 6 | path: '/authenticate', 7 | method: 'GET', 8 | summary: 'Get Authenticate', 9 | notes: '', 10 | type: 'User', 11 | nickname: 'getAuthenticate', 12 | produces: ['application/json'] 13 | } 14 | } 15 | var post = { 16 | 'spec': { 17 | description: 'Authenticate operations', 18 | path: '/authenticate', 19 | method: 'POST', 20 | summary: 'get Token', 21 | notes: '', 22 | type: 'User', 23 | nickname: 'createArticle', 24 | produces: ['application/json'], 25 | parameters: [{ 26 | name: 'body', 27 | description: 'get User Token.', 28 | required: true, 29 | type: 'User', 30 | paramType: 'body', 31 | allowMultiple: false 32 | }] 33 | } 34 | } 35 | 36 | swagger.addGet(list) 37 | .addPost(post) 38 | } 39 | -------------------------------------------------------------------------------- /documentation/Scripts.md: -------------------------------------------------------------------------------- 1 | ### Scripts 2 | 3 | Generate-ssl-certs.sh 4 | 5 | How to generate your own certs for https. 6 | 7 | ``` bash 8 | # used to generate your ssl certs - really good for testing ssl out 9 | bash ./scripts/generate-ssl-certs.sh 10 | # used to install mongodb into the project to help those out who dont know mongodb 11 | bash ./scripts/mongodb-install.sh 12 | # used to switch node versions easily with nvm 13 | bash ./scripts/nodejs-change-version.sh 14 | # used to install nodejs with nvm 15 | bash ./scripts/nodejs-install.sh 16 | # used to set proxies need to run our stack if your behind a firewall that needs a proxy 17 | bash ./scripts/set-proxies.sh 18 | # used to start of mongod regardless where it is install - as long as it is in the path 19 | bash ./scripts/start-mongod.sh 20 | # used to delete all proxy configs 21 | bash ./scripts/unset-proxies.sh 22 | # used to help users stack up todate on verisons of the mean stack by helping them merge 23 | node ./scripts/update-meanstackjs.js 24 | # used to install the tools 25 | node ./scripts/postinstall.js 26 | ``` 27 | -------------------------------------------------------------------------------- /client/modules/admin/admin.factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.admin') 6 | .factory('AdminUsersFactory', AdminUsersFactory) 7 | .factory('AdminErrorsFactory', AdminErrorsFactory) 8 | .factory('AdminLogsFactory', AdminLogsFactory) 9 | 10 | AdminUsersFactory.$inject = ['$resource'] 11 | AdminErrorsFactory.$inject = ['$resource'] 12 | AdminLogsFactory.$inject = ['$resource'] 13 | /* @ngInject */ 14 | function AdminUsersFactory ($resource) { 15 | return $resource('/api/admin/users/:id', { 16 | id: '@id' 17 | }, { 18 | update: { 19 | method: 'PUT' 20 | } 21 | }) 22 | } 23 | function AdminErrorsFactory ($resource) { 24 | return $resource('/api/admin/errors/:id', { 25 | id: '@id' 26 | }, { 27 | update: { 28 | method: 'PUT' 29 | } 30 | }) 31 | } 32 | function AdminLogsFactory ($resource) { 33 | return $resource('/api/admin/logs/:id', { 34 | id: '@id' 35 | }, { 36 | update: { 37 | method: 'PUT' 38 | } 39 | }) 40 | } 41 | }()) 42 | -------------------------------------------------------------------------------- /client/modules/chat/chat.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.chat', []) 6 | .controller('ChatController', ChatController) 7 | 8 | ChatController.$inject = ['$http', '$stateParams', 'logger', '$location', 'UserFactory', 'MeanSocket'] 9 | /* @ngInject */ 10 | function ChatController ($http, $stateParams, logger, $location, UserFactory, MeanSocket) { 11 | var vm = this 12 | vm.title = 'chat' 13 | vm.chat = {} 14 | vm.UserFactory = UserFactory 15 | activate() 16 | 17 | vm.messages = [] 18 | MeanSocket.on('message', function (msg) { 19 | var message = _.clone(msg) 20 | message.date = Date.now() 21 | vm.messages.unshift(message) 22 | }) 23 | vm.chat = function () { 24 | if (!vm.message) return 25 | MeanSocket.emit('message', { 26 | message: vm.message, 27 | user: vm.UserFactory.user.profile.name || 'Unknown' 28 | }) 29 | vm.message = '' 30 | } 31 | 32 | function activate () { 33 | logger.info('Activated Chat View') 34 | } 35 | } 36 | })() 37 | -------------------------------------------------------------------------------- /client/modules/core/core.route.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core') 6 | .run(appRun) 7 | 8 | /* @ngInject */ 9 | function appRun (routerHelper) { 10 | var otherwise = '/404' 11 | routerHelper.configureStates(getStates(), otherwise) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: '404', 18 | config: { 19 | url: '/404', 20 | templateUrl: 'modules/core/404.view.html', 21 | title: '404' 22 | } 23 | }, 24 | { 25 | state: '500', 26 | config: { 27 | url: '/500', 28 | templateUrl: 'modules/core/500.view.html', 29 | title: '500' 30 | } 31 | }, 32 | { 33 | state: 'debug', 34 | config: { 35 | url: '/debug', 36 | templateUrl: 'modules/core/debug.view.html', 37 | title: 'debug', 38 | controllerAs: 'vm', 39 | controller: function (browserInfo) { 40 | var vm = this 41 | vm.browserInfo = browserInfo 42 | } 43 | } 44 | } 45 | ] 46 | } 47 | })() 48 | -------------------------------------------------------------------------------- /client/modules/header/header.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.header') 6 | .controller('HeaderController', HeaderController) 7 | 8 | HeaderController.$inject = ['config', 'logger', '$http', 'UserFactory', '$rootScope', '$state'] 9 | /* @ngInject */ 10 | function HeaderController (config, logger, $http, UserFactory, $rootScope, $state) { 11 | var vm = this 12 | activate() 13 | vm.location = 'Header' 14 | vm.UserFactory = UserFactory 15 | vm.routes = $state.get() 16 | 17 | vm.logout = function () { 18 | vm.UserFactory = {} 19 | UserFactory.logout(vm) 20 | } 21 | 22 | $rootScope.$on('profileUpdated', function () { 23 | // if you want to do anything extra 24 | // vm.UserFactory = _.assign(vm.UserFactory, UserFactory) 25 | }) 26 | $rootScope.$on('loggedin', function () { 27 | // if you want to do anything extra 28 | vm.UserFactory = UserFactory 29 | }) 30 | 31 | $rootScope.$on('logout', function () { 32 | // if you want to do anything extra 33 | vm.UserFactory = {} 34 | }) 35 | 36 | function activate () { 37 | } 38 | } 39 | })() 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | - 9 5 | - 10 6 | os: 7 | - linux 8 | env: 9 | - NODE_ENV=nightwatch 10 | before_script: 11 | - wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.3.tgz -O /tmp/mongodb.tgz 12 | - tar -xvf /tmp/mongodb.tgz 13 | - mkdir /tmp/data 14 | - ${PWD}/mongodb-linux-x86_64-3.6.3/bin/mongod --dbpath /tmp/data & 15 | - until nc -z localhost 27017; do echo Waiting for MongoDB; sleep 1; done 16 | - npm i -g nsp 17 | - export CHROME_BIN=chromium-browser 18 | - export DISPLAY=:99.0 19 | - sh -e /etc/init.d/xvfb start 20 | - npm install selenium-standalone@latest -g 21 | - selenium-standalone install 22 | - 'selenium-standalone start 2>&1 &' 23 | - sleep 3 24 | script: 25 | - npm test 26 | after_script: 27 | - nsp check 28 | notifications: 29 | slack: meanstackjs:YtrF35Q7mPqPW5y6NHyDNvkh 30 | webhooks: 31 | urls: 32 | - https://webhooks.gitter.im/e/2f8affb0a488ea5f5b7c 33 | on_success: change # options: [always|never|change] default: always 34 | on_failure: always # options: [always|never|change] default: always 35 | on_start: never # options: [always|never|change] default: always 36 | sudo: false 37 | 38 | -------------------------------------------------------------------------------- /documentation/Testing.md: -------------------------------------------------------------------------------- 1 | ### Testing 2 | 3 | #### NPM Test / Everything 4 | 5 | ```bash 6 | # Make sure you haves a selenium sever on 7 | # https://www.npmjs.com/package/selenium-standalone 8 | npm test 9 | ``` 10 | 11 | #### Nightwatch / E2E 12 | 13 | ``` bash 14 | npm install -g nightwatch 15 | nightwatch 16 | # or 17 | npm run e2e 18 | ``` 19 | 20 | #### Karma / Frontend 21 | 22 | ``` bash 23 | npm install -g karma 24 | karma start tests/unit/karma.test.js 25 | # or 26 | npm run karma 27 | ``` 28 | 29 | #### Mocha & Chai / Backend 30 | 31 | ``` bash 32 | npm install -g mocha 33 | mocha tests/unit/mocha.test.js 34 | # or 35 | npm run mocha 36 | ``` 37 | 38 | #### Standard / JS Style 39 | 40 | ``` bash 41 | npm install -g standard 42 | standard 43 | # or 44 | npm run standard 45 | ``` 46 | 47 | #### Need help installing? 48 | 49 | Easiest way to start testing your whole system 50 | 51 | ``` bash 52 | npm run cli 53 | # select - Install Selenium Server 54 | # once installed - Start Selenium Server 55 | npm test 56 | ``` 57 | 58 | Note you must have mongodb running and if you dont then 59 | ``` bash 60 | npm run cli 61 | # the select - Install MongoDB 62 | # in a new window or tab select - Start Mongod 63 | ``` -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | License 2 | --------------------------------- 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2014-2018 Green Pioneer Solutions, LLC 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | 'Software'), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /documentation/CLI.md: -------------------------------------------------------------------------------- 1 | ### Command Line Interface (CLI) 2 | 3 | 4 | ```bash 5 | npm run cli 6 | ``` 7 | Options 8 | ``` 9 | new inquirer.Separator('Module Creation:'), 10 | 'Create Schema', 11 | 'Create A File or Files', 12 | 'Create Frontend Module', 13 | 'Create Backend Module', 14 | 'Create Frontend & Backend Module', 15 | new inquirer.Separator('Module Deletion:'), 16 | 'Remove Module', 17 | new inquirer.Separator('System Tasks:'), 18 | 'Start Mongod', 19 | 'Start Selenium Server', 20 | 'Install SSL Certs', 21 | 'Install Tools Dependencies', 22 | 'Install Bower Dependencies', 23 | 'Install MongoDB', 24 | 'Install NodeJS', 25 | 'Install Selenuim Server', 26 | 'Lint Code', 27 | 'Lint & Fix Code', 28 | 'Mean Stack JS Install Dependencies', 29 | 'Mean Stack JS Post Install', 30 | 'Seed Database', 31 | 'Linux Processes', 32 | 'Linux Kill Processes', 33 | 'Set Proxies', 34 | 'Delete Proxies', 35 | new inquirer.Separator('User Management:'), 36 | 'Change Password', 37 | 'Change User Roles', 38 | 'View User', 39 | 'Exit' 40 | ``` 41 | 42 | [![meanstackjs CLI](http://meanstackjs.com/images/CLI.png)](http://meanstackjs.com/) 43 | 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Expected Behavior 4 | 5 | 6 | 7 | ## Current Behavior 8 | 9 | 10 | 11 | ## Possible Solution 12 | 13 | 14 | 15 | ## Steps to Reproduce (for bugs) 16 | 17 | 18 | 1. 19 | 2. 20 | 3. 21 | 4. 22 | 23 | ## Context 24 | 25 | 26 | 27 | ## Your Environment 28 | 29 | * Version used: 30 | * Environment name and version (e.g. Chrome 39, node.js 5.4): 31 | * Operating System and version (desktop or mobile): 32 | * Link to your project: 33 | -------------------------------------------------------------------------------- /client/modules/core/404.view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

Page Not Found

5 |

We couldn't find what you're looking for on .

6 | Go Home 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |

What happened?

15 |

A 404 error status implies that the file or page that you're looking for could not be found.

16 |
17 |
18 |

What can I do?

19 |

If you're a site visitor

20 |

Please use your browser's back button and check that you're in the right place. If you need immediate assistance, please send us an email instead.

21 | Email us 22 |

If you're the site owner

23 |

Please check that you're in the right place and get in touch with your website provider if you believe this to be an error.

24 |
25 |
26 |
27 |
-------------------------------------------------------------------------------- /client/modules/blog/list.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

MeanStackJS Blog

5 | 6 |

7 |

Totals Blogs {{vm.count}}

8 | Using the official example template of creating a blog with Bootstrap. 9 |

10 |
11 |
12 |
13 |
14 |

No Blog Post Create One Now

15 | 16 |
17 |

{{value.title}}

18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 |
{{value.content}}
28 |
29 | 30 |
31 | 32 |
33 | 34 |
35 | -------------------------------------------------------------------------------- /server/db.js: -------------------------------------------------------------------------------- 1 | module.exports.mongoDB = mongoDB 2 | module.exports.disconnect = disconnect 3 | 4 | var mongoose = require('mongoose') 5 | var debug = require('debug')('meanstackjs:db') 6 | var glob = require('glob') 7 | var _ = require('lodash') 8 | var path = require('path') 9 | 10 | function mongoDB (self) { 11 | // Connect to MongoDb 12 | mongoose.Promise = global.Promise 13 | mongoose.set('useCreateIndex', true) 14 | mongoose.set('debug', self.settings.mongodb.debug) 15 | mongoose.connect(self.settings.mongodb.uri, self.settings.mongodb.options) 16 | mongoose.connection.on('error', function (error) { 17 | self.logger.warn('MongoDB Connection Error. Please make sure that MongoDB is running.') 18 | debug('MongoDB Connection Error ', error) 19 | }) 20 | mongoose.connection.on('open', function () { 21 | debug('MongoDB Connection Open ') 22 | }) 23 | // Register All Mongoose Models 24 | self.models = {} 25 | var files = glob.sync('server/modules/**/*.model.js') 26 | files.forEach(function (model, key) { 27 | var name = _.words(path.basename(model), /[^. ]+/g)[0] 28 | debug('Model: %s - %s', name, model) 29 | self.models[name] = mongoose.model(name, require('../' + model)) 30 | self.models[name].on('index', function (error) { 31 | if (error) throw error 32 | }) 33 | }) 34 | } 35 | function disconnect (cb) { 36 | if (!cb)cb = function () {} 37 | mongoose.disconnect(cb) 38 | } 39 | -------------------------------------------------------------------------------- /tests/e2e/seo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tags: ['seo'], 3 | 'Localhost Check SEO:blog list': function (browser) { 4 | browser 5 | .url(browser.launch_url + '/blog/list') 6 | .waitForElementVisible('body', 1000) 7 | .assert.visible('.blog-title') 8 | .verify.visible('.container') 9 | .end() 10 | }, 11 | 'Localhost Check SEO:404': function (browser) { 12 | browser 13 | .url(browser.launch_url + '404') 14 | .waitForElementVisible('body', 1000) 15 | .assert.title('Page Not Found') 16 | .verify.visible('.container') 17 | .end() 18 | }, 19 | 'Localhost Check SEO:500': function (browser) { 20 | browser 21 | .url(browser.launch_url + '500') 22 | .waitForElementVisible('body', 1000) 23 | .assert.title('Server Side Error') 24 | .verify.visible('.container') 25 | .end() 26 | }, 27 | 'Localhost Check SEO:signin': function (browser) { 28 | browser 29 | .url(browser.launch_url + 'signin') 30 | .waitForElementVisible('body', 1000) 31 | .assert.title('Signin to Mean Stack JS') 32 | .verify.visible('.container') 33 | .end() 34 | }, 35 | 'Localhost Check SEO:signup': function (browser) { 36 | browser 37 | .url(browser.launch_url + 'signup') 38 | .waitForElementVisible('body', 1000) 39 | .assert.title('Join Mean Stack JS') 40 | .verify.visible('.container') 41 | .end() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /server/authentication.js: -------------------------------------------------------------------------------- 1 | module.exports.passport = authentication 2 | 3 | var auth = require('./passport.js') 4 | var passport = require('passport') 5 | var session = require('express-session') 6 | var MongoStore = require('connect-mongo')(session) 7 | 8 | function authentication (self) { 9 | self.app.use(session({ 10 | name: self.settings.sessionName, 11 | resave: true, 12 | saveUninitialized: true, 13 | secret: self.settings.sessionSecret, 14 | store: new MongoStore({ 15 | url: self.settings.mongodb.uri, 16 | autoReconnect: true 17 | }) 18 | })) 19 | self.app.use(passport.initialize()) 20 | self.app.use(passport.session()) 21 | passport.serializeUser(auth.serializeUser) 22 | passport.deserializeUser(auth.deserializeUser) 23 | // Local Strategy 24 | passport.use(auth.passportStrategy) 25 | // Azure Strategy 26 | // passport.use(auth.passportAzureStrategy) 27 | // Instagram Strategy 28 | // passport.use(auth.passportInstagramStrategy) 29 | // Facebook Strategy 30 | // passport.use(auth.passportFacebookStrategy) 31 | // Twitter Strategy 32 | // passport.use(auth.passportTwitterStrategy) 33 | // GitHub Strategy 34 | // passport.use(auth.passportGitHubStrategy) 35 | // Google Strategy 36 | // passport.use(auth.passportGoogleStrategy) 37 | // LinkedIn Strategy 38 | // passport.use(auth.passportLinkedInStrategy) 39 | // OpenID Strategy 40 | // passport.use(auth.passportOpenIDStrategy) 41 | } 42 | -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | module.exports.configMiddleware = config 2 | 3 | var bodyParser = require('body-parser') 4 | var cookieParser = require('cookie-parser') 5 | var compress = require('compression') 6 | var expressValidator = require('express-validator') 7 | var methodOverride = require('method-override') 8 | var path = require('path') 9 | var statusMonitor = require('express-status-monitor') 10 | var queryParameters = require('express-query-parameters')() 11 | 12 | function config (self) { 13 | self.app.enable('trust proxy') 14 | self.app.disable('x-powered-by') 15 | self.app.set('view engine', 'html') 16 | self.app.set('views', path.join(self.dir, '/client')) 17 | self.app.set('port', self.port) 18 | self.app.use(statusMonitor({ 19 | path: '/api/status' 20 | })) 21 | self.app.use(compress()) 22 | self.app.use(bodyParser.json(self.settings.bodyparser.json)) 23 | self.app.use(bodyParser.urlencoded(self.settings.bodyparser.urlencoded)) 24 | self.app.use(expressValidator(self.settings.expresValidator)) 25 | self.app.use(methodOverride()) 26 | self.app.use(cookieParser()) 27 | queryParameters.config({ 28 | settings: { 29 | schema: ['_id', 'id', '__v', 'created', 'title', 'content', 'user', 'email', 'roles'], // the names people can search 30 | adapter: 'mongoose' // 31 | } 32 | }) 33 | self.app.use(queryParameters.middleware()) 34 | self.app.use(require('./prerenderer')) 35 | } 36 | -------------------------------------------------------------------------------- /server/security.js: -------------------------------------------------------------------------------- 1 | module.exports.securityMiddleware = security 2 | 3 | var cors = require('cors') 4 | var contentLength = require('express-content-length-validator') 5 | var helmet = require('helmet') 6 | var hpp = require('hpp') 7 | var throttler = require('mongo-throttle') 8 | 9 | function security (self) { 10 | // LIMIT/THROTTLE THE REQUESTS 11 | if (self.settings.security.throttler.active) self.app.use(throttler(self.settings.security.throttler.options)) 12 | // HELMET SECURITY MIDDLEWARE 13 | self.app.use(helmet(self.settings.security.helmet.options)) 14 | if (self.settings.security.contentSecurityPolicy.active)self.app.use(helmet.contentSecurityPolicy(self.settings.security.contentSecurityPolicy.options)) 15 | if (self.settings.security.hpkp.active)self.app.use(helmet.hpkp(self.settings.security.hpkp.options)) 16 | if (self.settings.cache.headers.active)self.app.use(helmet.noCache()) 17 | // HTTP Parameter Pollution attacks 18 | if (self.settings.security.hpp.active)self.app.use(hpp(self.settings.security.hpp.options)) 19 | // CORS 20 | if (self.settings.security.cors.active)self.app.use(cors(self.settings.security.cors.options)) 21 | if (self.settings.security.cors.preflight)self.app.options('*', cors(self.settings.security.cors.options)) // include before other routes 22 | // CONTENT LENGTH 23 | if (self.settings.security.contentLength.active) self.app.use(contentLength.validateMax(self.settings.security.contentLength.options)) 24 | } 25 | -------------------------------------------------------------------------------- /commands/template/client/list.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

MeanStackJS <%= Name %>s

5 |

Using the official example template of creating a <%= name %> module with Bootstrap.

6 |
7 |
8 |
9 |
10 |
11 |

No <%= Name %> Data Points

12 | Create One Now 13 |
14 | 15 |
16 |

{{value.title}}

17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 |

{{value.content}}

27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | -------------------------------------------------------------------------------- /client/modules/user/forgot.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 |
9 | 10 |
11 |
12 |
13 |
14 |

Enter your email address below and we will send you password reset instructions.

15 | 16 | 17 |

Must be a valid email address

18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /client/modules/core/500.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

Internal Server Error

6 |

The web server is returning an internal error for .

7 | Go Home 8 |
9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |

What happened?

19 |

A 500 error status implies there is a problem with the web server

20 |
21 |
22 |

What can I do?

23 |

If you're a site visitor

24 |

Nothing you can do at the moment. If you need immediate assistance, please send us an email instead. We apologize for any inconvenience.

25 | Email us 26 |

If you're the site owner

27 |

This error can only be fixed by server admins, please contact your website provider.

28 |
29 |
30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /documentation/File-Naming-Structure.md: -------------------------------------------------------------------------------- 1 | ### File Naming Structure 2 | 3 | 4 | #### Modules 5 | 6 | We have implemented modules with a specific file naming convention for server & client side coding. Each module has a unique such as `blog`. Inside of each module you specific files named as such `UNIQUE_NAME.FILE_TYPE_IDENTIFIER.FILE_EXTENSION` 7 | 8 | #### Available Keywords to use for `FILE_TYPE_IDENTIFIER` 9 | 10 | | FRONTEND | BACKEND | 11 | | ---------------------------------- | ------------------------------------------------------------ | 12 | | `module` | `models` | 13 | | `controller` | `controller` | 14 | | `routes` | `routes` | 15 | | `config` | `spec` | 16 | | `service` | | 17 | | `provider` | | 18 | | `directive` | | 19 | | `style` | | 20 | | `json` | | 21 | | `view` | | 22 | | `spec` | | 23 | 24 | Once everything is set up properly we then register all modules and all of its content appropriately on `server.js` startup. 25 | 26 | 27 | Examples on the frontend include : 28 | 29 | - `blog.controller.js` 30 | - `email.controller.js` 31 | - `blog.factory.js` 32 | - `auth.factory.js` 33 | - `blog.module.js` 34 | - `blog.routes.js.js` 35 | - `blog.spec.css` 36 | - `blog.style.css` 37 | - `blog.style.scss` 38 | - `list.style.less` 39 | - `create.view.html` 40 | 41 | Examples on the backend include : 42 | 43 | - `blog.controller.js` 44 | - `blog.model.js` 45 | - `blog.routes.js` 46 | - `blog.spec.js` 47 | 48 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Motivation and Context 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## Screenshots (if appropriate): 16 | 17 | ## Types of changes 18 | 19 | - [ ] Bug fix (non-breaking change which fixes an issue) 20 | - [ ] New feature (non-breaking change which adds functionality) 21 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 22 | 23 | ## Checklist: 24 | 25 | 26 | - [ ] My code follows the code style of this project. 27 | - [ ] My change requires a change to the documentation. 28 | - [ ] I have updated the documentation accordingly. 29 | - [ ] I have read the **CONTRIBUTING** document. 30 | - [ ] I have added tests to cover my changes. 31 | - [ ] All new and existing tests passed. 32 | -------------------------------------------------------------------------------- /client/modules/core/core.factory.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.core') 6 | .factory('MeanSocket', MeanSocket) 7 | 8 | MeanSocket.$inject = ['$rootScope', '$http'] 9 | 10 | function MeanSocket ($rootScope, $http) { 11 | var socket = io.connect(window.location.hostname + ':8282/') 12 | return { 13 | on: function (eventName, callback) { 14 | socket.on(eventName, function () { 15 | var args = arguments 16 | $rootScope.$apply(function () { 17 | callback.apply(socket, args) 18 | }) 19 | }) 20 | }, 21 | once: function (eventName, callback) { 22 | socket.once(eventName, function () { 23 | var args = arguments 24 | $rootScope.$apply(function () { 25 | callback.apply(socket, args) 26 | }) 27 | }) 28 | }, 29 | emit: function (eventName, data, callback) { 30 | socket.emit(eventName, data, function () { 31 | $rootScope.$apply(function () { 32 | var args = arguments 33 | if (callback) { 34 | callback.apply(socket, args) 35 | } 36 | }) 37 | }) 38 | }, 39 | removeAllListeners: function () { 40 | return socket.removeAllListeners.apply(socket, arguments) 41 | }, 42 | disconnect: function (close) { 43 | return socket.disconnect(close) 44 | }, 45 | connect: function () { 46 | return socket.connect() 47 | } 48 | } 49 | } 50 | }()) 51 | -------------------------------------------------------------------------------- /server/prerenderer.js: -------------------------------------------------------------------------------- 1 | module.exports = prerenderer 2 | 3 | var Horseman = require('node-horseman') 4 | var isBot = require('isbot') 5 | var debug = require('debug')('meanstackjs:prerenderer') 6 | var MEAN_STACK_UA = 'Mean Stack Prerenderer' 7 | 8 | function shouldRenderFromPhantom (req) { 9 | var userAgent = req.headers['user-agent'] 10 | var bufferAgent = req.headers['x-bufferbot'] 11 | var prerenderedPage = false 12 | 13 | if (!userAgent || userAgent === MEAN_STACK_UA) return false 14 | if (req.method !== 'GET' && req.method !== 'HEAD') return false 15 | 16 | // does it contain _escaped_fragment_, show prerendered page 17 | var parsedQuery = req.query 18 | if (parsedQuery._escaped_fragment_ !== undefined) prerenderedPage = true 19 | 20 | // is it a bot then show prerendered page 21 | if (isBot(userAgent)) prerenderedPage = true 22 | 23 | // is it a bufferbot then show prerendered page 24 | if (bufferAgent) prerenderedPage = true 25 | 26 | return prerenderedPage 27 | } 28 | 29 | function prerenderer (req, res, next) { 30 | if (shouldRenderFromPhantom(req)) { 31 | var escapedFragment = req.query._escaped_fragment_ 32 | var fullHref = req.protocol + '://' + req.headers.host + (escapedFragment ? req.path + '#!/' + escapedFragment : req.originalUrl) 33 | new Horseman() 34 | .userAgent(MEAN_STACK_UA) 35 | .open(fullHref) 36 | .html().then(function (html) { 37 | res.send(html) 38 | }).catch(function (error) { 39 | debug(error) 40 | next() 41 | }).close() 42 | return 43 | } 44 | next() 45 | } 46 | -------------------------------------------------------------------------------- /client/modules/admin/users.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |

Users

7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 28 | 29 | 32 | 33 | 34 |
#NameRolesEmail
{{$index + 1}} 22 | 23 | {{value.profile.name}} 24 | 26 |
{{role}}
27 |
30 | {{value.email}} 31 |
35 |
36 |
37 |
38 |
-------------------------------------------------------------------------------- /client/modules/admin/admin.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.admin', []) 6 | .controller('AdminController', AdminController) 7 | 8 | AdminController.$inject = ['$http', '$stateParams', 'AdminUsersFactory', 'AdminErrorsFactory', 'AdminLogsFactory', 'logger', '$location', 'UserFactory'] 9 | /* @ngInject */ 10 | function AdminController ($http, $stateParams, AdminUsersFactory, AdminErrorsFactory, AdminLogsFactory, logger, $location, UserFactory) { 11 | var vm = this 12 | vm.title = 'System' 13 | vm.view = $stateParams.view ? 'modules/admin/' + $stateParams.view + '.view.html' : 'modules/admin/home.view.html' 14 | vm.admin = {} 15 | vm.UserFactory = UserFactory 16 | vm.listUsers = function () { 17 | AdminUsersFactory.query(function (success) { 18 | vm.users = success 19 | }, function (error) { 20 | logger.error(error.statusText, error, error.data) 21 | }) 22 | } 23 | vm.listErrors = function () { 24 | AdminErrorsFactory.query(function (success) { 25 | vm.errors = success 26 | }, function (error) { 27 | logger.error(error.statusText, error, error.data) 28 | }) 29 | } 30 | vm.listLogs = function () { 31 | AdminLogsFactory.get(function (success) { 32 | vm.logs = success 33 | }, function (error) { 34 | logger.error(error.statusText, error, error.data) 35 | }) 36 | } 37 | 38 | activate() 39 | function activate () { 40 | vm.listUsers() 41 | vm.listErrors() 42 | logger.info('Activated Admin View') 43 | } 44 | } 45 | })() 46 | -------------------------------------------------------------------------------- /server/modules/system/system.controller.js: -------------------------------------------------------------------------------- 1 | exports.testing = testing 2 | exports.pug = pug 3 | exports.status = status 4 | exports.proxy = proxy 5 | 6 | var request = require('request') 7 | var _ = require('lodash') 8 | var path = require('path') 9 | 10 | function testing (mail, settings) { 11 | return function (req, res, next) { 12 | res.status(200).send({ 13 | query: req.queryParameters 14 | }) 15 | } 16 | } 17 | 18 | function pug (settings) { 19 | return function (req, res, next) { 20 | res.send(require('pug').renderFile(path.join(__dirname, 'setting.view.pug'), { settings: settings })) 21 | } 22 | } 23 | 24 | function status (req, res, next) { 25 | res.status(200).send() 26 | } 27 | 28 | function proxy (req, res, next) { 29 | try { 30 | var url = _.replace(req.originalUrl, '/api/proxy/', '') 31 | var requestOptions = { 32 | url: url, 33 | qs: req.query, 34 | method: req.method, 35 | headers: _.assign({ 36 | 'content-type': 'application/json' 37 | }, req.headers), 38 | rejectUnauthorized: false, 39 | json: true 40 | } 41 | if (req.query.proxy) { 42 | requestOptions.proxy = req.query.proxy 43 | delete req.query.proxy 44 | requestOptions.qs = req.query 45 | } 46 | if (req.method === 'POST' || req.method === 'PUT') { 47 | requestOptions.body = JSON.stringify(req.body) 48 | } 49 | req.pipe(request(requestOptions)).on('error', function (error) { 50 | next(error) 51 | }).pipe(res).on('error', function (error) { 52 | next(error) 53 | }) 54 | } catch (error) { 55 | next(error) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/e2e/general.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tags: ['general'], 3 | 'Localhost Check:page': function (browser) { 4 | browser 5 | .url(browser.launch_url) 6 | .waitForElementVisible('body', 1000) 7 | .verify.visible('.container') 8 | .end() 9 | }, 10 | 'Localhost Check:admin': function (browser) { 11 | browser 12 | .url(browser.launch_url + '/admin') 13 | .waitForElementVisible('body', 1000) 14 | .verify.visible('.container') 15 | .end() 16 | }, 17 | 'Localhost Check:blog list': function (browser) { 18 | browser 19 | .url(browser.launch_url + '/blog/list') 20 | .waitForElementVisible('body', 1000) 21 | .verify.visible('.container') 22 | .end() 23 | }, 24 | 'Localhost Check:404': function (browser) { 25 | browser 26 | .url(browser.launch_url + '404') 27 | .waitForElementVisible('body', 1000) 28 | .verify.visible('.container') 29 | .end() 30 | }, 31 | 'Localhost Check:500': function (browser) { 32 | browser 33 | .url(browser.launch_url + '500') 34 | .waitForElementVisible('body', 1000) 35 | .verify.visible('.container') 36 | .end() 37 | }, 38 | 'Localhost Check:signin': function (browser) { 39 | browser 40 | .url(browser.launch_url + 'signin') 41 | .waitForElementVisible('body', 1000) 42 | .verify.visible('.container') 43 | .end() 44 | }, 45 | 'Localhost Check:signup': function (browser) { 46 | browser 47 | .url(browser.launch_url + 'signup') 48 | .waitForElementVisible('body', 1000) 49 | .verify.visible('.container') 50 | .end() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /scripts/nodejs-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # if you need more help installing node - https://gist.github.com/isaacs/579814 3 | # 4 | # Uncomment if you need for a linux server in the cloud 5 | # CURRENT=`pwd` 6 | # DOWNLOADSDIR="$CURRENT/downloads/node-v6.9.2-linux-x64.tar.gz" 7 | # if [ ! -e index.js ] 8 | # then 9 | # echo "Please run the nodejs-install.sh script from the main root directory" 10 | # echo "i.e: bash scripts/nodejs-install.sh" 11 | # echo "Or by npm run nodejs-install" 12 | # exit -1 13 | # fi 14 | # mkdir -p ./downloads 15 | # cd ./downloads 16 | # curl -O https://nodejs.org/dist/v6.9.2/node-v6.9.2-linux-x64.tar.gz 17 | # cd /usr/local 18 | # tar --strip-components=1 -xzf "$DOWNLOADSDIR" 19 | # node -v 20 | 21 | 22 | if [ "$(uname)" == "Darwin" ]; then 23 | echo "You're using macOS. Checking for Node.js installation." 24 | elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then 25 | echo "You're using Linux. Checking for Node.js installation." 26 | elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then 27 | echo "Please download Node.js from https://nodejs.org and install it." 28 | exit 1 29 | fi 30 | 31 | if which node >/dev/null; then 32 | echo "Node.js is already installed." 33 | exit 34 | fi 35 | 36 | install_node () { 37 | export NVM_DIR="$HOME/.nvm" 38 | [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm 39 | echo "nvm is installed. Installing Node.js v6.9.2." 40 | nvm install 6.9.2 41 | } 42 | 43 | NVM_DIRECTORY="$HOME/.nvm" 44 | if [ -d "$NVM_DIRECTORY" ]; then 45 | install_node 46 | else 47 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash 48 | install_node 49 | fi 50 | -------------------------------------------------------------------------------- /server/token.js: -------------------------------------------------------------------------------- 1 | exports.createKey = createKey 2 | exports.checkKey = checkKey 3 | 4 | var mongoose = require('mongoose') 5 | var User = mongoose.model('users') 6 | var settings = require('../configs/settings').get() 7 | var jwt = require('jsonwebtoken') 8 | var debug = require('debug')('meanstackjs:users') 9 | 10 | function createKey (user, apikey) { 11 | return jwt.sign({ 12 | _id: user._id 13 | }, apikey || user.apikey, settings.jwt.options) 14 | } 15 | 16 | function checkKey (token, cb) { 17 | var decoded = jwt.decode(token, { complete: true }) 18 | if (!decoded) return cb({ message: 'Nothing to decode' }) 19 | if (!decoded.payload) return cb({ message: 'No payload to decode' }) 20 | if (!decoded.payload._id) return cb({ message: 'No user id was found in decode' }) 21 | User.findOne({ 22 | _id: decoded.payload._id 23 | }, function (error, user) { 24 | if (error) cb(error) 25 | if (!user) { 26 | cb({ message: 'Authentication failed. User not found.' }) 27 | } else { 28 | debug('middleware verify user: ', user.email) 29 | jwt.verify(token, user.apikey, function (error, decoded) { 30 | if (error) { 31 | debug('middleware verify error: ', error) 32 | switch (error.name) { 33 | case 'TokenExpiredError': 34 | cb({ message: 'It appears your token has expired' }) // Date(error.expiredAt) 35 | break 36 | case 'JsonWebTokenError': 37 | cb({ message: 'It appears you have invalid signature Token Recieved:' + token }) 38 | break 39 | } 40 | } else { 41 | cb(null, user) 42 | } 43 | }) 44 | } 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /nightwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_folders": ["tests/e2e"], 3 | "output_folder" : "tools/nightwatch/reports", 4 | "custom_commands_path" : "", 5 | "custom_assertions_path" : "", 6 | "page_objects_path" : "", 7 | "globals_path": "tests/globals", 8 | 9 | "selenium" : { 10 | "start_process" : false, 11 | "server_path" : "", 12 | "log_path" : "", 13 | "host" : "127.0.0.1", 14 | "port" : 4444, 15 | "cli_args" : { 16 | "webdriver.chrome.driver": "", 17 | "webdriver.ie.driver" : "" 18 | } 19 | }, 20 | 21 | "test_settings" : { 22 | "default" : { 23 | "launch_url" : "http://localhost:3000/", 24 | "selenium_port" : 4444, 25 | "selenium_host" : "localhost", 26 | "pathname": "/wd/hub", 27 | "silent": true, 28 | "screenshots" : { 29 | "enabled" : true, 30 | "path" : "tools/nightwatch/reports/screenshots" 31 | }, 32 | "desiredCapabilities" : { 33 | "browserName" : "firefox", 34 | "javascriptEnabled": true, 35 | "databaseEnabled": true, 36 | "locationContextEnabled": true, 37 | "applicationCacheEnabled": true, 38 | "browserConnectionEnabled": true, 39 | "webStorageEnabled": true, 40 | "acceptSslCerts": true, 41 | "rotatable": true, 42 | "nativeEvents": true, 43 | "chromeOptions": { 44 | "args":["disable-web-security", "ignore-certificate-errors"] 45 | } 46 | } 47 | }, 48 | "chrome" : { 49 | "desiredCapabilities": { 50 | "browserName": "chrome" 51 | } 52 | }, 53 | "edge" : { 54 | "desiredCapabilities": { 55 | "browserName": "MicrosoftEdge" 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /client/modules/index/index.style.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Styles here should be specific to this module. It will be aggregated and compiled when the environment starts up. 3 | ----------------------------- 4 | */ 5 | @import 'global-variables.styles.scss'; 6 | 7 | .jumbotron { 8 | margin-bottom: 0; 9 | } 10 | 11 | .banner { 12 | padding: 7rem 0; 13 | width: 100%; 14 | } 15 | 16 | .banner--contribute { 17 | background-color: #f8f8f8; 18 | } 19 | 20 | .banner--features { 21 | background-color: darken($gray-light, 25%); 22 | color: lighten($gray-light, 25%); 23 | } 24 | 25 | .tagline { 26 | margin: 0 0 3rem 0; 27 | text-align: center; 28 | } 29 | 30 | .tagline-heading { 31 | color: $meanstack-grey; 32 | } 33 | 34 | .tagline-heading--light { 35 | color: white; 36 | } 37 | 38 | .tagline-subheading { 39 | color: $meanstack-blue; 40 | font-size: 2.1rem; 41 | } 42 | 43 | .tagline-subheading--light { 44 | color: $meanstack-red; 45 | } 46 | 47 | .feature { 48 | margin-bottom: 3rem; 49 | } 50 | 51 | .feature-icon, 52 | .feature-text { 53 | display: inline-block; 54 | } 55 | 56 | .feature-icon { 57 | color: darken($gray-light, 5%); 58 | font-size: 4rem; 59 | } 60 | 61 | .feature-text { 62 | font-size: 1.8rem; 63 | margin-left: 1rem; 64 | max-width: 70%; 65 | } 66 | 67 | .miscFeatures { 68 | background-color: darken($gray-light, 5%); 69 | margin-top: 2rem; 70 | } 71 | 72 | .stackLink { 73 | display: block; 74 | margin-bottom: 2rem; 75 | } 76 | 77 | .stackInfo { 78 | margin-bottom: 4rem; 79 | position: relative; 80 | &:after { 81 | content: ""; 82 | position: absolute; 83 | bottom: -20px; 84 | left: 86px; 85 | height: 2px; 86 | background-color: #ddd; 87 | width: 55%; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /server.socketio.js: -------------------------------------------------------------------------------- 1 | module.exports = SocketIO 2 | /** 3 | * Mean Stack SocketIO Server File 4 | * @name SocketIO 5 | * @function 6 | * @param {Object} opts the options passed to create the server 7 | * @param {Function} done the callback function 8 | * MIT Licensed 9 | */ 10 | 11 | var express = require('express') 12 | var debug = require('debug')('meanstackjs:socketio') 13 | var fs = require('fs') 14 | var settings = require('./configs/settings.js').get() 15 | var glob = require('glob') 16 | 17 | function SocketIO (opts, done) { 18 | var self = this 19 | self.logger = require('./server/logger.js').logger 20 | self.app = express() 21 | if (settings.https.active) { 22 | self.socketServer = require('https').createServer({ 23 | key: fs.readFileSync(settings.https.key), 24 | cert: fs.readFileSync(settings.https.cert) 25 | }, self.app) 26 | } else { 27 | self.socketServer = require('http').createServer(self.app) 28 | } 29 | 30 | self.io = require('socket.io')(self.socketServer) 31 | 32 | self.io.on('connection', function (socket) { 33 | var files = glob.sync('server/modules/**/*.socket.js') 34 | files.forEach(function (socketFile) { 35 | debug('Sockets: %s', socketFile) 36 | require('./' + socketFile)(self.io, socket) 37 | }) 38 | socket.on('system', function (msg) { 39 | io.emit('system', msg) 40 | }) 41 | }) 42 | 43 | self.app.set('port', settings.socketio.port) 44 | self.socketServer.listen(self.app.get('port')) 45 | 46 | debug('Socketio listening on port %d', self.app.get('port')) 47 | self.logger.info('Socketio listening on port %d', self.app.get('port')) 48 | done(null) 49 | } 50 | 51 | var run = require('./run.js') 52 | if (!module.parent) { 53 | run(SocketIO) 54 | } 55 | -------------------------------------------------------------------------------- /client/modules/blog/blog.routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.blog') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: 'create', 18 | config: { 19 | url: '/blog/create', 20 | templateUrl: 'modules/blog/create.view.html', 21 | controller: 'BlogController', 22 | controllerAs: 'vm', 23 | resolve: { 24 | loggedin: function (UserFactory) { 25 | return UserFactory.checkLoggedin() 26 | } 27 | } 28 | } 29 | }, 30 | { 31 | state: 'edit', 32 | config: { 33 | url: '/blog/edit/:id', 34 | templateUrl: 'modules/blog/edit.view.html', 35 | controller: 'BlogController', 36 | controllerAs: 'vm', 37 | resolve: { 38 | loggedin: function (UserFactory) { 39 | return UserFactory.checkLoggedin() 40 | } 41 | } 42 | } 43 | }, 44 | { 45 | state: 'list', 46 | config: { 47 | url: '/blog/list', 48 | templateUrl: 'modules/blog/list.view.html', 49 | controller: 'BlogController', 50 | controllerAs: 'vm' 51 | } 52 | }, 53 | { 54 | state: 'view', 55 | config: { 56 | url: '/blog/view/:id', 57 | templateUrl: 'modules/blog/view.view.html', 58 | controller: 'BlogController', 59 | controllerAs: 'vm' 60 | } 61 | } 62 | 63 | ] 64 | } 65 | })() 66 | -------------------------------------------------------------------------------- /server/modules/admin/admin.routes.js: -------------------------------------------------------------------------------- 1 | var admin = require('./admin.controller.js') 2 | 3 | module.exports = function (app, auth, mail, settings, models, logger) { 4 | // USERS 5 | app.get('/api/admin/users', auth.isAdmin, admin.getUsers) 6 | app.get('/api/admin/users/:userId', auth.isAdmin, admin.getUsersById) 7 | // POST 8 | app.post('/api/admin/users', auth.isAdmin, admin.postUsers) 9 | // PUT 10 | app.put('/api/admin/users/:userId', auth.isAdmin, admin.putUsers) 11 | // DELETE 12 | app.delete('/api/admin/users/:userId', auth.isAdmin, admin.deleteUsers) 13 | // PARAM 14 | app.param('userId', admin.paramUsers) 15 | 16 | // ERRORS 17 | app.get('/api/admin/errors/', auth.isAdmin, admin.getErrors) 18 | app.get('/api/admin/errors/:errorId', auth.isAdmin, admin.getErrorsById) 19 | // POST 20 | app.post('/api/admin/errors', auth.isAdmin, admin.postErrors) 21 | // PUT 22 | app.put('/api/admin/errors/:errorId', auth.isAdmin, admin.putErrors) 23 | // DELETE 24 | app.delete('/api/admin/errors/:errorId', auth.isAdmin, admin.deleteErrors) 25 | // PARAM 26 | app.param('errorId', admin.paramErrors) 27 | 28 | // LOGS 29 | app.get('/api/admin/logs/', auth.isAdmin, function (req, res, next) { 30 | logger.query({ 31 | from: req.query.from || (new Date() - 24 * 60 * 60 * 1000), 32 | until: req.query.until || new Date(), 33 | limit: req.query.limit || 10, 34 | start: req.query.start || 0, 35 | order: req.query.order || 'desc', 36 | fields: req.query.fields || undefined 37 | }, function (error, results) { 38 | if (error) return next(error) 39 | if (req.query.select) return res.status(200).send(results[req.query.select]) 40 | return res.status(200).send(results) 41 | }) 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /configs/certificates/certExample.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEmzCCA4OgAwIBAgIJAMEqKippbOWgMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYD 3 | VQQGEwJVUzELMAkGA1UECBMCVFgxEzARBgNVBAcTCkZvcnQgV29ydGgxEDAOBgNV 4 | BAoTB0dQUyBsbGMxEzARBgNVBAsTCk1lYW4gU3RhY2sxDDAKBgNVBAMTA0dQUzEp 5 | MCcGCSqGSIb3DQEJARYadGVzdEBncmVlbnBpb25lZXJzb2x1dGlvbnMwHhcNMTYw 6 | NjExMjIyOTM4WhcNMTcwNjExMjIyOTM4WjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV 7 | BAgTAlRYMRMwEQYDVQQHEwpGb3J0IFdvcnRoMRAwDgYDVQQKEwdHUFMgbGxjMRMw 8 | EQYDVQQLEwpNZWFuIFN0YWNrMQwwCgYDVQQDEwNHUFMxKTAnBgkqhkiG9w0BCQEW 9 | GnRlc3RAZ3JlZW5waW9uZWVyc29sdXRpb25zMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA6L3Sqm35sYJUd//0Zs40Sv94dgzERloneknNL2+4pBLyN7/z 11 | YImvlUB0gkgjZX1R73QP5wWEK2P1BpFnzlwtno/ARbu4o1wbqwZkHGsdEZ2l/fpw 12 | nj+QOlSNOR68batpvML3YZuYS6Kq58uzwfQG1cOOLiB0CVkHECrkOSsMa3W70spu 13 | kY8eF46C2J4GBDvwsny+YQwpnr7szIaBX3dDmLxo/FCPKyfqONBeGxfET3yq4x4X 14 | rb0SiRL6CQHEuoKfhF8Du2K2DUqVMsE+lgbF0tjR0uHQdtI5cdQpORd/rt78rxri 15 | e7/JZTG8dF73lQpYdrB3rbLfIvGCO3wFRLE70wIDAQABo4H3MIH0MB0GA1UdDgQW 16 | BBT9L5pcjE5ZiK7j3POjkRqNvZgCKDCBxAYDVR0jBIG8MIG5gBT9L5pcjE5ZiK7j 17 | 3POjkRqNvZgCKKGBlaSBkjCBjzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlRYMRMw 18 | EQYDVQQHEwpGb3J0IFdvcnRoMRAwDgYDVQQKEwdHUFMgbGxjMRMwEQYDVQQLEwpN 19 | ZWFuIFN0YWNrMQwwCgYDVQQDEwNHUFMxKTAnBgkqhkiG9w0BCQEWGnRlc3RAZ3Jl 20 | ZW5waW9uZWVyc29sdXRpb25zggkAwSoqKmls5aAwDAYDVR0TBAUwAwEB/zANBgkq 21 | hkiG9w0BAQUFAAOCAQEAxdfV3A8DZrli5WIrOYsUY8yKWqLUwJyBjjhtp8jrgiur 22 | XGgNRf9AxvZ/gc5tZ4sxn+VCtOqbu2lT3sNu5PSKBtZHIUh+IKx1Xz79vD1r3T1m 23 | CiGpnyupkeJgtB6RW9EmWrYxDLgf5oNblztqEoUyZiNh0S3yWXjTHICzahTqZrV6 24 | cw1zpbiitf5h8q/N/lO/DDXnW+QFpBXE1fZZ9oOWa0+xiof/BXIxqhoNCi/lg8cC 25 | Wxlv5073xJKUMz/WSYSFn0xJ2Inmy/Qg+OWfA8e2Rs6cvBeWExci36iLuAXmmt58 26 | VilmwSuDzAS/JzuhBPwYXdnzqWsoNhz7WACA5arqzg== 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /configs/certificates/keyExample.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA6L3Sqm35sYJUd//0Zs40Sv94dgzERloneknNL2+4pBLyN7/z 3 | YImvlUB0gkgjZX1R73QP5wWEK2P1BpFnzlwtno/ARbu4o1wbqwZkHGsdEZ2l/fpw 4 | nj+QOlSNOR68batpvML3YZuYS6Kq58uzwfQG1cOOLiB0CVkHECrkOSsMa3W70spu 5 | kY8eF46C2J4GBDvwsny+YQwpnr7szIaBX3dDmLxo/FCPKyfqONBeGxfET3yq4x4X 6 | rb0SiRL6CQHEuoKfhF8Du2K2DUqVMsE+lgbF0tjR0uHQdtI5cdQpORd/rt78rxri 7 | e7/JZTG8dF73lQpYdrB3rbLfIvGCO3wFRLE70wIDAQABAoIBAAmy11OIz63o+3Ig 8 | tWOPVjiF2tQ4hflUim6bIrTGWBBmRbezBQZR1oJGtFQ1g1wYU9DBqmP7I93XBX/n 9 | kUbVKoWAAggl4XTVQsXmt0dD42s3gZJK3GSLy4vSuCvYLwv256oZCcwEet00AyEz 10 | qOL9M0e3JXagnZVCI3w1/Vqwg4z6v6f4NT8d0M8qQ11aiVB2ejHILusHh3H4TO50 11 | CxMr1NFcOlRposTdvdC7tpab/u8i4NwfNSg4ucUoBKYeoHzBMiagCq3OSacHLsoS 12 | uNanat5nkQI9vbkDswlh1huAKJPksTDqQm9NaI42DrImUfdwPqnDnz6tcesA+MAd 13 | J7lkuEkCgYEA9GcRmIjV0ZBiS9LiWS8ltmt4ZPWymlhVzifCVkhgoJryajgTWqsY 14 | 07reKl1a7fkWJrEiNL91jxLHkcsTfjFNIruPL/C+eXo6RNG8sH+upUanW7EeSdMQ 15 | WCW10KD/itvK1iMzzWzmV0+moUTqmhdLM8TYcZZAgXB9gIt+fDYLsHcCgYEA88kZ 16 | LdYxYo7yPB7FRIBd4EObY+Xq/1butNX7PLFkENXCJnOgjQk+jKbcPLW3EXlh7G64 17 | XlgfBO0Uxp+smgVxNS9YADzpd2mlkBjiiUV4gv1jeqY9Y7K3SGbwjkZUIRBzwYh8 18 | X/8FtBycLOHuZuM+5kOUn/tyr2UhEi1r4X63YoUCgYBV/RVxx2MDUntjFhVRL4dj 19 | QTigvNlT+JRn7hEv7lMg7qMvv/7/PYeEpxCXczUU2Thz8IqKaHpiFkdlAkAffBUZ 20 | jUf5pAhAEUMDB5ANwT6fI9aqKgzwCHSNrubjOmHuZxpccRI+ynvYaEvGHcs039Ez 21 | q6RDgou7fuqJGYstBI7kTQKBgD6p/Izpt/wLnnyRtEdtb7QL7M969DL6V5WoQ1JQ 22 | jtY8/BECO8zFCY0B/y6jzxDw0JkDxOSLZj3P6z07IhTdPUJcjxRQk/qb73Dg1KpQ 23 | by/Mjluii7kq4S39N+x6a3msTvT6bm4GkaLAj+yBjtRnqW1rBbMx4ULwjdWsU0S9 24 | W8o5AoGBAI3OaykHehas2McZOERb3AsDYQPaPpkpQfI8pz6H3Hh6/H4XBQsfL8KZ 25 | 1yRteM+tQ8hAjKhme05u+edqLvnysdXnpk7o/TJYXVo1leokOcpaye3/PfOSuT6p 26 | FlF8rHJhDhZrdhtuVbHubnr6twXV7MKUyboTxYZv/l6sN5SRUl5r 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | MAINTAINER GreenPioneer 3 | # Install Utilities 4 | RUN apt-get update -q 5 | # RUN apt-get install -yqq wget aptitude htop vim git traceroute dnsutils curl ssh sudo tree tcpdump nano psmisc gcc make build-essential libfreetype6 libfontconfig libkrb5-dev 6 | RUN apt-get install -yqq wget vim git curl ssh build-essential 7 | 8 | # Install NodeJS 9 | RUN curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - 10 | RUN sudo apt-get install -yq nodejs 11 | 12 | # Install Meanstackjs Prerequisites 13 | RUN npm install --quiet -g mocha pm2 mongo-express nodemon node-inspector 14 | 15 | RUN mkdir /opt/meanstackjs 16 | WORKDIR /opt/meanstackjs 17 | 18 | # Copies the local package.json file to the container 19 | # and utilities docker container cache to not needing to rebuild 20 | # and install node_modules/ everytime we build the docker, but only 21 | # when the local package.json file changes. 22 | # Install npm packages 23 | ADD package.json /opt/meanstackjs/package.json 24 | RUN npm install --quiet 25 | 26 | # Install bower packages 27 | # ADD bower.json /opt/meanstackjs/bower.json 28 | # ADD .bowerrc /opt/meanstackjs/.bowerrc 29 | # RUN bower install --quiet --allow-root --config.interactive=false 30 | 31 | # Share local directory on the docker container 32 | ADD . /opt/meanstackjs 33 | 34 | # Machine cleanup 35 | RUN npm cache clean 36 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 37 | 38 | # Set development environment as default 39 | ENV NODE_ENV development 40 | 41 | # Ports generic 42 | EXPOSE 80:80 43 | EXPOSE 443:443 44 | 45 | # Port 3000 for Meanstackjs server 46 | EXPOSE 3000:3000 47 | 48 | # Port 5858 for node debug 49 | EXPOSE 5858:5858 50 | 51 | # Port 35729 for livereload 52 | EXPOSE 35729:35729 53 | 54 | # Run Meanstackjs server 55 | CMD ["npm", "start"] 56 | -------------------------------------------------------------------------------- /client/modules/admin/errors.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |

Errors

7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 31 | 36 | 37 | 38 |
#TimestampLevelMessageMeta
{{$index + 1}} 23 | {{value.timestamp}} 24 | 26 | {{value.level}} 27 | 29 | {{value.message}} 30 | 32 | Collapse 33 | Expand 34 |
{{value.meta.stack}}
35 |
39 |
40 |
41 |
42 |
-------------------------------------------------------------------------------- /commands/template/client/routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: '<%= name %>Create', 18 | config: { 19 | url: '/<%= name %>/create', 20 | templateUrl: 'modules/<%= name %>/create.view.html', 21 | controller: '<%= Name %>Controller', 22 | controllerAs: 'vm', 23 | resolve: { 24 | loggedin: function (UserFactory) { 25 | return UserFactory.checkLoggedin() 26 | } 27 | } 28 | } 29 | }, 30 | { 31 | state: '<%= name %>Edit', 32 | config: { 33 | url: '/<%= name %>/edit/:id', 34 | templateUrl: 'modules/<%= name %>/edit.view.html', 35 | controller: '<%= Name %>Controller', 36 | controllerAs: 'vm', 37 | resolve: { 38 | loggedin: function (UserFactory) { 39 | return UserFactory.checkLoggedin() 40 | } 41 | } 42 | } 43 | }, 44 | { 45 | state: '<%= name %>List', 46 | config: { 47 | url: '/<%= name %>/list', 48 | templateUrl: 'modules/<%= name %>/list.view.html', 49 | controller: '<%= Name %>Controller', 50 | controllerAs: 'vm' 51 | } 52 | }, 53 | { 54 | state: '<%= name %>View', 55 | config: { 56 | url: '/<%= name %>/view/:id', 57 | templateUrl: 'modules/<%= name %>/view.view.html', 58 | controller: '<%= Name %>Controller', 59 | controllerAs: 'vm' 60 | } 61 | } 62 | 63 | ] 64 | } 65 | })() 66 | -------------------------------------------------------------------------------- /client/modules/user/signin.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 |
9 | 10 |
11 |
12 |
13 |
14 | 15 | 16 |

Must be a valid email address

17 |
18 |
19 | 20 | 21 |
22 |
23 | Forgot your password? 24 |
25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /tools/agenda/index.js: -------------------------------------------------------------------------------- 1 | module.exports = setupToolAgenda 2 | 3 | var debug = require('debug')('meanstackjs:tools') 4 | var path = require('path') 5 | var fs = require('fs') 6 | var Agenda = require('agenda') 7 | var Agendash = require('agendash') 8 | var backup = require('mongodb-backup') 9 | var restore = require('mongodb-restore') 10 | 11 | function setupToolAgenda (self) { 12 | debug('started setupToolAgenda') 13 | if (self.settings.agendash.active) { 14 | self.agenda = new Agenda(self.settings.agendash.options) 15 | if (!fs.existsSync(self.dir + '/backups/')) { 16 | fs.mkdirSync(self.dir + '/backups/') 17 | } 18 | 19 | self.agenda.define('backup', function (job, done) { 20 | var db = {} 21 | if (!fs.statSync(path.join(self.dir, 'backups/'))) done('No Root Directory ') 22 | if (job.attrs.data.uri) db.uri = job.attrs.data.uri 23 | else done('No URI was passed') 24 | if (job.attrs.data.collections) db.collections = job.attrs.data.collections 25 | try { 26 | backup(db) 27 | } catch (err) { 28 | done(err) 29 | } 30 | done() 31 | }) 32 | 33 | self.agenda.define('restore', function (job, done) { 34 | var db = {} 35 | if (!fs.statSync(path.join(self.dir, 'backups/'))) done('No Root Directory ') 36 | if (job.attrs.data.uri) db.uri = job.attrs.data.uri 37 | else done('No URI was passed') 38 | try { 39 | restore(db) 40 | } catch (err) { 41 | done(err) 42 | } 43 | done() 44 | }) 45 | 46 | self.agenda.on('ready', function () { 47 | // //every 3 mins or every minute 48 | // self.agenda.every('3 minutes', 'restore') 49 | // self.agenda.every('*/1 * * * *', 'backup') 50 | self.agenda.start() 51 | }) 52 | 53 | self.app.use('/agenda', /* require('./server/middleware.js').isAdmin, */ Agendash(self.agenda)) 54 | } 55 | debug('end setupToolAgenda') 56 | } 57 | -------------------------------------------------------------------------------- /documentation/Roadmap.md: -------------------------------------------------------------------------------- 1 | Welcome to those of you here reading the roadmap. we are very open to feedback and to debate what would be a great fit in the stack. With that being said lets start the conversation right here and get it planned into the start. Please feel free to create a issue/feature request. 2 | 3 | There will be more info to come later in the roadmap. 4 | 5 | Meanstackjs 1.x - Goal is to support Enterprises 6 | ---------------- 7 | 8 | We will default to what supports most of versions of node, browsers & users. 1.x will try to keep production ready at all time with the most stable code base. 9 | 10 | * ES5 11 | * [Expressjs 4](http://expressjs.com/en/4x/api.html) 12 | * [Boostrap 3](https://getbootstrap.com/docs/3.3/) 13 | * [Angular](https://angularjs.org/) 1.x 14 | * [MongoDB](https://www.mongodb.com/download-center#community) 3.x 15 | * [Nodejs](https://github.com/nodejs/LTS#lts_schedule) 6.x - 9.x 16 | * [John Papa Angular Style](https://github.com/johnpapa/angular-styleguide/tree/master/a1) 17 | * [NightwatchJS](http://nightwatchjs.org/) 0.x - 1.x 18 | 19 | Meanstackjs 2.x - Goal is to support Open Source Comp 20 | ---------------- 21 | 22 | We plan to really use forward thinking technologies with the all the newest stuff. 23 | 24 | * ES6 25 | * [Expressjs 5](http://expressjs.com/en/guide/migrating-5.html) 26 | * [Boostrap 4](https://getbootstrap.com/) 27 | * [Angular](https://angular.io/) 5.x > 28 | * [MongoDB](https://www.mongodb.com/download-center#community) 3.x - 4.x 29 | * [Nodejs](https://github.com/nodejs/LTS#lts_schedule) 10.x - 14.x 30 | * [John Papa Angular 2 Style ](https://github.com/johnpapa/angular-styleguide/tree/master/a2) 31 | * [NightwatchJS](http://nightwatchjs.org/) 1.x - 2.x 32 | 33 | 34 | Meanstack will try to support regardless the version 35 | --------------- 36 | * CSS, SCSS & LESS (support Materialize & Foundation) 37 | * [Standard JS](http://standardjs.com/) 38 | * [Docker](https://www.docker.com/) 39 | * [Swagger Api](http://swagger.io/) 40 | 41 | Potential Mern Stack Js on the rise in the future. 42 | 43 | -------------------------------------------------------------------------------- /tests/e2e/admin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // tags: ['admin'], 3 | // 'Localhost Check:login check admin as admin': function (browser) { 4 | // browser 5 | // .url(browser.launch_url + 'signin') 6 | // .waitForElementVisible('body', 3000) 7 | // .verify.visible('#email') 8 | // .verify.visible('#password') 9 | // .setValue('input[type=email]', 'jason@greenpioneersolutions.com') 10 | // .setValue('input[type=password]', 'truetrue1!') 11 | // .waitForElementVisible('button[type=submit]', 3000) 12 | // .pause(2000) 13 | // .click('button[type=submit]') 14 | // .pause(1000) 15 | // .click('#simple-dropdown') 16 | // .pause(1000) 17 | // .verify.visible('#admin') 18 | // .click('#admin') 19 | // .pause(2000) 20 | // .click('#Users') 21 | // .pause(16000) 22 | // .assert.containsText('body', 'jason@greenpioneersolutions.com') 23 | // .end() 24 | // }, 25 | // 'Localhost Check:login check admin as user': function (browser) { 26 | // browser 27 | // .url(browser.launch_url + 'signin') 28 | // .waitForElementVisible('body', 3000) 29 | // .verify.visible('#email') 30 | // .verify.visible('#password') 31 | // .setValue('input[type=email]', 'accounting@greenpioneersolutions.com') 32 | // .setValue('input[type=password]', 'truetrue1!') 33 | // .waitForElementVisible('button[type=submit]', 3000) 34 | // .pause(2000) 35 | // .click('button[type=submit]') 36 | // .pause(1000) 37 | // .click('#simple-dropdown') 38 | // .pause(1000) 39 | // .verify.hidden('#admin') 40 | // .end() 41 | // }, 42 | // 'Localhost Check:login check admin page - not authorized': function (browser) { 43 | // browser 44 | // .url(browser.launch_url + 'signin') 45 | // .waitForElementVisible('body', 3000) 46 | // .url(browser.launch_url + '/admin') 47 | // .pause(2000) 48 | // .waitForElementVisible('#toast-container', 2000) 49 | // .end() 50 | // } 51 | } 52 | -------------------------------------------------------------------------------- /configs/seo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-template-curly-in-string */ 2 | module.exports = { 3 | '/': { 4 | title: process.env.SEO_TITLE || 'Mean Stack JS Demo' 5 | }, 6 | '/404': { 7 | title: process.env.SEO_404 || 'Page Not Found' 8 | }, 9 | '/500': { 10 | title: process.env.SEO_500 || 'Server Side Error' 11 | }, 12 | '/signin': { 13 | title: process.env.SEO_LOG_IN || 'Signin to Mean Stack JS' 14 | }, 15 | '/signup': { 16 | title: process.env.SEO_SIGN_UP || 'Join Mean Stack JS ' 17 | }, 18 | '/account': { 19 | title: process.env.SEO_ACCOUNT || '<%= user.profile.name %> Account' 20 | }, 21 | '/forgot': { 22 | title: process.env.SEO_FORGOT || 'Forgot Your Password ' 23 | }, 24 | '/reset/': { 25 | title: process.env.SEO_RESET || 'reset ' 26 | }, 27 | '/blog/create': { 28 | title: process.env.SEO_CREATE || 'Create a New Blog' 29 | }, 30 | '/blog/edit/': { 31 | title: process.env.SEO_EDIT || 'Edit Your Blog' 32 | }, 33 | '/blog/list': { 34 | title: process.env.SEO_LIST || 'Blog List' 35 | }, 36 | '/blog/view/:id': { 37 | title: '<%= blog.title %> - <%= blog.user.profile.name %> ', 38 | keywords: '<%= blog.tags %>', 39 | description: '<%= blog.content %> ', 40 | ogUrl: '<%= path %>', 41 | twitterUrl: '<%= path %>', 42 | canonical: '<%= path %>', 43 | ogTitle: '<%= blog.title %> - <%= blog.user.profile.name %> ', 44 | twitterTitle: '<%= blog.title %> - <%= blog.user.profile.name %> ', 45 | ogDescription: '<%= blog.content %> ', 46 | twitterDescription: '<%= blog.content %> ', 47 | hook: function (self, data, cb) { 48 | data.blog = { 49 | tags: process.env.SEO_TAGS || ['Add', 'Tags', 'To Blog', 'Mean Stack JS'] 50 | } 51 | self.models.blog.findOne({ _id: data.params.id }).populate('user').lean().then(function (blog) { 52 | data.blog = Object.assign({}, data.blog, blog) 53 | cb(null, data) 54 | }).catch(function (error) { 55 | cb(error) 56 | }) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/globals.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'nightwatch' 2 | var MeanStack = require('../server.mean.js') 3 | var run = require('../run.js') 4 | var HtmlReporter = require('nightwatch-html-reporter') 5 | var path = require('path') 6 | var reporter = new HtmlReporter({ 7 | openBrowser: true, 8 | reportsDirectory: path.join(__dirname, '../tools/nightwatch/reports'), 9 | // The filename that the html report will be saved as. 10 | reportFilename: 'index.html', 11 | 12 | // The theme that will be used to generate the html report. 13 | // This should match a directory under the lib/themes directory. 14 | themeName: 'default', 15 | 16 | // If true then only errors will be shown in the report. 17 | hideSuccess: false 18 | }) 19 | module.exports = { 20 | reporter: reporter.fn, 21 | // this controls whether to abort the test execution when an assertion failed and skip the rest 22 | // it's being used in waitFor commands and expect assertions 23 | abortOnAssertionFailure: true, 24 | 25 | // this will overwrite the default polling interval (currently 500ms) for waitFor commands 26 | // and expect assertions that use retry 27 | waitForConditionPollInterval: 300, 28 | 29 | // default timeout value in milliseconds for waitFor commands and implicit waitFor value for 30 | // expect assertions 31 | waitForConditionTimeout: 5000, 32 | 33 | // this will cause waitFor commands on elements to throw an error if multiple 34 | // elements are found using the given locate strategy and selector 35 | throwOnMultipleElementsReturned: true, 36 | 37 | // controls the timeout time for async hooks. Expects the done() callback to be invoked within this time 38 | // or an error is thrown 39 | asyncHookTimeout: 20000, 40 | 41 | before: function (done) { 42 | run(MeanStack, function (error) { 43 | if (error) console.log(error) 44 | require('./seed.js')(function () { 45 | done() 46 | }) 47 | }) 48 | }, 49 | 50 | beforeEach: function (browser, cb) { 51 | cb() 52 | }, 53 | 54 | after: function (cb) { 55 | cb() 56 | process.exit(0) // doing this because the cb() wasnt working 57 | }, 58 | 59 | afterEach: function (browser, cb) { 60 | cb() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /documentation/FAQ.md: -------------------------------------------------------------------------------- 1 | ### Frequently Asked Questions (FAQ) 2 | 3 | #### 1. Error: listen EACCES 0.0.0.0 4 | 5 | Try Running in Sudo or Admin access 6 | sudo node index.js 7 | 8 | ``` bash 9 | [UNCAUGHT EXCEPTION] 10 | Error: listen EACCES 0.0.0.0:843 11 | at Object.exports._errnoException (util.js:856:11) 12 | at exports._exceptionWithHostPort (util.js:879:20) 13 | at Server._listen2 (net.js:1218:19) 14 | at listen (net.js:1267:10) 15 | at Server.listen (net.js:1363:5) 16 | at Mean.async.parallel.server (/Users/humphrey/Documents/repos/meanstackjs/server.mean.js:77:22) 17 | ``` 18 | 19 | #### 2. Error: connect ECONNREFUSED 127.0.0.1:27017 20 | 21 | MongoDB is not running or your uri is not pointing to the correct place 22 | 23 | ``` bash 24 | [UNCAUGHT EXCEPTION] 25 | Error: connect ECONNREFUSED 127.0.0.1:27017 26 | at Object.exports._errnoException (util.js:856:11) 27 | at exports._exceptionWithHostPort (util.js:879:20) 28 | at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1057:14) 29 | ``` 30 | 31 | 32 | #### 3. xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun 33 | 34 | Have you sud­denly started get­ting the fol­low­ing error in your project? 35 | 36 | ``` bash 37 | xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 38 | ```` 39 | Solution 40 | 41 | ``` bash 42 | xcode-select --install 43 | ``` 44 | [Credit](http://tips.tutorialhorizon.com/2015/10/01/xcrun-error-invalid-active-developer-path-library-developer-commandline-tools-missing-xcrun/) 45 | 46 | #### 4. Angularjs: Error: [ng:areq] Argument 'HomeController' is not a function, got undefined 47 | 48 | This creates a new module/app: 49 | 50 | `var myApp = angular.module('myApp',[]);` 51 | 52 | While this accesses an already created module (notice the omission of the second argument): 53 | 54 | `var myApp = angular.module('myApp');` 55 | 56 | Since you use the first approach on both scripts you are basically overriding the module you previously created. 57 | 58 | On the second script being loaded, use `var myApp = angular.module('myApp');` 59 | 60 | [Credit](http://stackoverflow.com/a/25895387) -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## How to contribute 4 | 5 | Support and contributions from the open source community are essential for keeping 6 | Mean Stack JS up to date. We are always looking for the quality contributions and 7 | will be happy to accept your Pull Requests as long as those adhere to some basic rules: 8 | 9 | * Please make sure that your contribution fits well in the project's style & concept: 10 | * [Standard JS](http://standardjs.com/) 11 | * [John Papa Angular Style](https://github.com/johnpapa/angular-styleguide/tree/master/a1) 12 | * [Pass All Test](https://travis-ci.org/greenpioneersolutions/meanstackjs) 13 | * [Roadmap](https://github.com/greenpioneersolutions/meanstackjs/wiki/Roadmap) 14 | 15 | ## Creating an Issue 16 | 17 | Before you create a new Issue: 18 | * Check the [Issues](https://github.com/greenpioneersolutions/meanstackjs/issues) on Github to ensure one doesn't already exist. 19 | * Place use one of these topics in the beginning of your issue title- Contrib, Hotfix, Error, Help or Feature. 20 | * Clearly describe the issue, including the steps to reproduce the issue. 21 | * If it's a new feature, enhancement, or restructure, Explain your reasoning on why you think it should be added, as well as a particular use case. 22 | 23 | ## Making Changes 24 | 25 | * Create a topic branch from the development branch with the issue number EX. `#200_make_changes` 26 | * Use `standard || npm run standard` to verify your style - `npm install -g standard` if you dont have it already 27 | * Keep git commit messages clear and appropriate 28 | * Make Sure you have added any tests necessary to test your code. `npm test` 29 | * Update the Documentation to go along with any changes in functionality / improvements. 30 | 31 | ## Submitting the Pull Request 32 | 33 | * Push your changes to your topic branch on your fork of the repo. 34 | * Submit a pull request from your topic branch to the development branch 35 | * We use [GitFlow](https://guides.github.com/introduction/flow/) 36 | * Be sure to tag any issues your pull request is taking care of / contributing to. EX. `#201 add and updated this` 37 | * By adding "Closes #xyz" to a commit message will auto close the issue once the pull request is merged in. 38 | 39 | -------------------------------------------------------------------------------- /configs/environments/test.js: -------------------------------------------------------------------------------- 1 | var mongodbUri = process.env.DB_PORT_27017_TCP_ADDR || process.env.MONGODB || process.env.MONGOLAB_URI || 'mongodb://localhost/test' 2 | module.exports = { 3 | minify: process.env.MINIFY || 'concat', // 'concat' all files or 'minify' concat and minfy or 'default' leave as is 4 | html: { 5 | title: process.env.HTML_TITLE || 'Test MEANSTACKJS' 6 | }, 7 | logger: 'common', 8 | cdn: process.env.CDN || false, 9 | buildreq: { 10 | console: false 11 | }, 12 | maxcdn: { 13 | zoneId: process.env.MAXCDN_ZONE_ID || false 14 | }, 15 | mongoexpress: { 16 | port: process.env.MONGOEXPRESSPORT || 8081 17 | }, 18 | socketio: { 19 | port: process.env.SOCKETIOPORT || 8282 20 | }, 21 | http: { 22 | active: process.env.HTTP_ACTIVE || true, 23 | port: process.env.PORT || 3000 24 | }, 25 | https: { 26 | useNewUrlParser: true, 27 | active: process.env.HTTPS_ACTIVE || false, 28 | redirect: true, 29 | port: process.env.HTTPSPORT || 3043, 30 | key: process.env.HTTPS_KEY || './configs/certificates/keyExample.pem', 31 | cert: process.env.HTTPS_CERT || './configs/certificates/certExample.pem' 32 | }, 33 | throttle: { 34 | rateLimit: { 35 | ttl: 600, 36 | max: 1000 37 | }, 38 | mongoose: { 39 | uri: mongodbUri 40 | } 41 | }, 42 | mongodb: { 43 | uri: mongodbUri, 44 | // Database options that will be passed directly to mongoose.connect 45 | // Below are some examples. 46 | // See http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connect-options 47 | // and http://mongoosejs.com/docs/connections.html for more information 48 | 49 | options: { 50 | autoIndex: false, // Don't build indexes 51 | reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect 52 | reconnectInterval: 500, // Reconnect every 500ms 53 | poolSize: 10, // Maintain up to 10 socket connections 54 | // If not connected, return errors immediately rather than waiting for reconnect 55 | bufferMaxEntries: 0 56 | } 57 | }, 58 | agendash: { 59 | active: true, 60 | options: { 61 | db: { 62 | address: mongodbUri 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /configs/environments/development.js: -------------------------------------------------------------------------------- 1 | var mongodbUri = process.env.DB_PORT_27017_TCP_ADDR || process.env.MONGODB || process.env.MONGOLAB_URI || 'mongodb://localhost/dev' 2 | module.exports = { 3 | minify: process.env.MINIFY || 'default', // 'concat' all files or 'minify' concat and minfy or 'default' leave as is 4 | html: { 5 | title: process.env.HTML_TITLE || 'Development MEANSTACKJS' 6 | }, 7 | logger: 'dev', 8 | cdn: process.env.CDN || false, 9 | buildreq: { 10 | console: true 11 | }, 12 | maxcdn: { 13 | zoneId: process.env.MAXCDN_ZONE_ID || false 14 | }, 15 | mongoexpress: { 16 | port: process.env.MONGOEXPRESSPORT || 8081 17 | }, 18 | socketio: { 19 | port: process.env.SOCKETIOPORT || 8282 20 | }, 21 | http: { 22 | active: process.env.HTTP_ACTIVE || true, 23 | port: process.env.PORT || 3000 24 | }, 25 | https: { 26 | active: process.env.HTTPS_ACTIVE || false, 27 | redirect: true, 28 | port: process.env.HTTPSPORT || 3043, 29 | key: process.env.HTTPS_KEY || './configs/certificates/keyExample.pem', 30 | cert: process.env.HTTPS_CERT || './configs/certificates/certExample.pem' 31 | }, 32 | throttle: { 33 | rateLimit: { 34 | ttl: 600, 35 | max: 20000 36 | }, 37 | mongoose: { 38 | uri: mongodbUri 39 | } 40 | }, 41 | mongodb: { 42 | uri: mongodbUri, 43 | // Database options that will be passed directly to mongoose.connect 44 | // Below are some examples. 45 | // See http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connect-options 46 | // and http://mongoosejs.com/docs/connections.html for more information 47 | options: { 48 | useNewUrlParser: true, 49 | autoIndex: false, // Don't build indexes 50 | reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect 51 | reconnectInterval: 500, // Reconnect every 500ms 52 | poolSize: 10, // Maintain up to 10 socket connections 53 | // If not connected, return errors immediately rather than waiting for reconnect 54 | bufferMaxEntries: 0 55 | } 56 | }, 57 | agendash: { 58 | active: true, 59 | options: { 60 | db: { 61 | address: mongodbUri 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /configs/environments/production.js: -------------------------------------------------------------------------------- 1 | var mongodbUri = process.env.DB_PORT_27017_TCP_ADDR || process.env.MONGODB || process.env.MONGOLAB_URI || 'mongodb://localhost/prod' 2 | module.exports = { 3 | minify: process.env.MINIFY || 'minify', // 'concat' all files or 'minify' concat and minfy or 'default' leave as is 4 | html: { 5 | title: process.env.HTML_TITLE || 'MEANSTACKJS' 6 | }, 7 | logger: 'combined', 8 | cdn: process.env.CDN || false, 9 | buildreq: { 10 | console: false 11 | }, 12 | maxcdn: { 13 | zoneId: process.env.MAXCDN_ZONE_ID || false 14 | }, 15 | mongoexpress: { 16 | port: process.env.MONGOEXPRESSPORT || 8081 17 | }, 18 | socketio: { 19 | port: process.env.SOCKETIOPORT || 8282 20 | }, 21 | http: { 22 | active: process.env.HTTP_ACTIVE || true, 23 | port: process.env.PORT || 3000 24 | }, 25 | https: { 26 | active: process.env.HTTPS_ACTIVE || false, 27 | redirect: true, 28 | port: process.env.HTTPSPORT || 3043, 29 | key: process.env.HTTPS_KEY || './configs/certificates/keyExample.pem', 30 | cert: process.env.HTTPS_CERT || './configs/certificates/certExample.pem' 31 | }, 32 | throttle: { 33 | rateLimit: { 34 | ttl: 600, 35 | max: 1000 36 | }, 37 | mongoose: { 38 | uri: mongodbUri 39 | } 40 | }, 41 | mongodb: { 42 | uri: mongodbUri, 43 | // Database options that will be passed directly to mongoose.connect 44 | // Below are some examples. 45 | // See http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connect-options 46 | // and http://mongoosejs.com/docs/connections.html for more information 47 | 48 | options: { 49 | useNewUrlParser: true, 50 | autoIndex: false, // Don't build indexes 51 | reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect 52 | reconnectInterval: 500, // Reconnect every 500ms 53 | poolSize: 10, // Maintain up to 10 socket connections 54 | // If not connected, return errors immediately rather than waiting for reconnect 55 | bufferMaxEntries: 0 56 | } 57 | }, 58 | agendash: { 59 | active: true, 60 | options: { 61 | db: { 62 | address: mongodbUri 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -------------------- 2 | # OSX Files 3 | # -------------------- 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | Icon 8 | ._* 9 | .Spotlight-V100 10 | .Trashes 11 | 12 | # -------------------- 13 | # Eclipse or Nodeclipse "Enide Studio" Files 14 | # -------------------- 15 | # recommended to add to Git SCM 16 | # or generate with `nodeclipse -p` command 17 | .project 18 | .settings/ 19 | .*.md.html 20 | 21 | 22 | # -------------------- 23 | # IntelliJ Files 24 | # -------------------- 25 | *.iml 26 | *.ipr 27 | *.iws 28 | .idea/ 29 | 30 | # -------------------- 31 | # Netbeans Files 32 | # -------------------- 33 | nbproject/private/ 34 | build/ 35 | nbbuild/ 36 | nbdist/ 37 | nbactions.xml 38 | nb-configuration.xml 39 | 40 | # -------------------- 41 | # Node Files 42 | # -------------------- 43 | npm-debug.log 44 | node_modules/ 45 | 46 | # -------------------- 47 | # SASS Files 48 | # -------------------- 49 | .sass-cache/ 50 | client/styles/global-configs.styles.scss 51 | 52 | 53 | # -------------------- 54 | # Bower Files 55 | # -------------------- 56 | .bower-*/ 57 | bower_components 58 | components 59 | 60 | # -------------------- 61 | # App Files 62 | # -------------------- 63 | client/uploads 64 | 65 | 66 | # -------------------- 67 | # vim Files 68 | # -------------------- 69 | *.swp 70 | 71 | # -------------------- 72 | # Files 73 | # -------------------- 74 | files/ 75 | 76 | # -------------------- 77 | # Global Compiled files 78 | # -------------------- 79 | client/styles/compiled 80 | client/scripts/compiled 81 | client/styles/downloaded 82 | client/scripts/downloaded 83 | 84 | # -------------------- 85 | # Babel Compiled files 86 | # -------------------- 87 | server/dist/ 88 | 89 | # -------------------- 90 | # Tool Reports reports 91 | # -------------------- 92 | tools/*/reports 93 | tools/nightwatch/reports/index.html 94 | 95 | 96 | # -------------------- 97 | # Mean Stack Folders 98 | # -------------------- 99 | database/ 100 | downloads/ 101 | backups/ 102 | 103 | # -------------------- 104 | # Mean Stack ENV 105 | # -------------------- 106 | .env 107 | 108 | # -------------------- 109 | # Mean Stack Logs 110 | # -------------------- 111 | logs/ 112 | -------------------------------------------------------------------------------- /configs/environments/nightwatch.js: -------------------------------------------------------------------------------- 1 | var mongodbUri = process.env.DB_PORT_27017_TCP_ADDR || process.env.MONGODB || process.env.MONGOLAB_URI || 'mongodb://localhost/nightwatch' 2 | module.exports = { 3 | minify: process.env.MINIFY || 'default', // 'concat' all files or 'minify' concat and minfy or 'default' leave as is - Added process env for testing 4 | html: { 5 | title: process.env.HTML_TITLE || 'Nightwatch E2E MEANSTACKJS' 6 | }, 7 | logger: false, 8 | cdn: process.env.CDN || false, 9 | buildreq: { 10 | console: false 11 | }, 12 | maxcdn: { 13 | zoneId: process.env.MAXCDN_ZONE_ID || false 14 | }, 15 | mongoexpress: { 16 | port: process.env.MONGOEXPRESSPORT || 8081 17 | }, 18 | socketio: { 19 | port: process.env.SOCKETIOPORT || 8282 20 | }, 21 | http: { 22 | active: process.env.HTTP_ACTIVE || true, 23 | port: process.env.PORT || 3000 24 | }, 25 | https: { 26 | active: process.env.HTTPS_ACTIVE || false, 27 | redirect: true, 28 | port: process.env.HTTPSPORT || 3043, 29 | key: process.env.HTTPS_KEY || './configs/certificates/keyExample.pem', 30 | cert: process.env.HTTPS_CERT || './configs/certificates/certExample.pem' 31 | }, 32 | throttle: { 33 | rateLimit: { 34 | ttl: 600, 35 | max: 10000 36 | }, 37 | mongoose: { 38 | uri: mongodbUri 39 | } 40 | }, 41 | mongodb: { 42 | uri: mongodbUri, 43 | // Database options that will be passed directly to mongoose.connect 44 | // Below are some examples. 45 | // See http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html#mongoclient-connect-options 46 | // and http://mongoosejs.com/docs/connections.html for more information 47 | 48 | options: { 49 | useNewUrlParser: true, 50 | autoIndex: false, // Don't build indexes 51 | reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect 52 | reconnectInterval: 500, // Reconnect every 500ms 53 | poolSize: 10, // Maintain up to 10 socket connections 54 | // If not connected, return errors immediately rather than waiting for reconnect 55 | bufferMaxEntries: 0 56 | } 57 | }, 58 | agendash: { 59 | active: true, 60 | options: { 61 | db: { 62 | address: mongodbUri 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /server/logger.js: -------------------------------------------------------------------------------- 1 | module.exports.loggerMiddleware = middleware 2 | 3 | var morgan = require('morgan') 4 | var pathExists = require('is-there') 5 | var fs = require('fs') 6 | var path = require('path') 7 | var winston = require('winston') 8 | require('winston-daily-rotate-file') 9 | var MongoDB = require('winston-mongodb').MongoDB 10 | var WinstonFile = (process.env.NODE_ENV !== 'production' ? winston.transports.File : winston.transports.DailyRotateFile) 11 | var settings = require('../configs/settings').get() 12 | 13 | if (!pathExists(path.join(__dirname, '/../logs/'))) { 14 | fs.mkdirSync(path.join(__dirname, '/../logs/')) 15 | } 16 | 17 | var logger = new (winston.Logger)({ 18 | transports: [ 19 | new (winston.transports.Console)({ 20 | prettyPrint: true, 21 | colorize: true, 22 | showLevel: false, 23 | timestamp: false, 24 | handleExceptions: true 25 | }), 26 | new (WinstonFile)({ 27 | name: 'error', 28 | filename: 'logs/error-meanstackjs.log', 29 | datePattern: 'yyyy-MM-dd.', 30 | prepend: true, 31 | level: 'error', 32 | handleExceptions: true, 33 | json: true, 34 | maxsize: 52428800, // 50MB 35 | maxFiles: 5 36 | }), 37 | new (WinstonFile)({ 38 | name: 'info', 39 | filename: 'logs/info-meanstackjs.log', 40 | datePattern: 'yyyy-MM-dd.', 41 | prepend: true, 42 | handleExceptions: true, 43 | json: true, 44 | maxsize: 52428800, // 50MB 45 | maxFiles: 5 46 | }), 47 | new (WinstonFile)({ 48 | name: 'warn', 49 | filename: 'logs/warn-meanstackjs.log', 50 | datePattern: 'yyyy-MM-dd.', 51 | prepend: true, 52 | level: 'warn', 53 | handleExceptions: true, 54 | json: true, 55 | maxsize: 52428800, // 50MB 56 | maxFiles: 5 57 | }), 58 | new (MongoDB)({ 59 | level: 'error', 60 | db: settings.mongodb.uri, 61 | collection: 'errors', 62 | handleExceptions: true, 63 | json: true, 64 | maxsize: 52428800, // 50MB 65 | maxFiles: 5 66 | }) 67 | ], 68 | exitOnError: false 69 | }) 70 | 71 | function middleware (self) { 72 | if (self.settings.logger) { 73 | self.app.use(morgan(self.settings.logger, { 74 | stream: { 75 | write: function (message) { 76 | self.logger.info(message.replace(/\n$/, '')) 77 | } 78 | } 79 | })) 80 | } 81 | } 82 | 83 | module.exports.logger = logger 84 | -------------------------------------------------------------------------------- /documentation/Errors.md: -------------------------------------------------------------------------------- 1 | ### Errors 2 | 3 | #### Where do we catch our errors ? 4 | 5 | 1. Run.js - uncaughtException 6 | 7 | ``` javascript 8 | process.on('uncaughtException', function (logErr) { 9 | error.log(err,function(logErr){ 10 | // We will tell the process to quick because its not recommend to continue on 11 | // we recommend pm2 or something that will restart your processes automatically 12 | process.exit(1) 13 | }) 14 | }) 15 | ``` 16 | 17 | 2. Run.js - unhandledRejection 18 | 19 | ``` javascript 20 | // We do not quit on a unhandled reject because this is only going to work in later versions of node 21 | // and we defer to how you uses promises to handle your errors here but we will still log them for you 22 | process.on('unhandledRejection', function (reason) { 23 | debug('System Error unhandledRejection:' + reason) 24 | console.error('[UNHANDLED REJECTION]') 25 | console.error(error.log(reason)) 26 | }) 27 | ``` 28 | 29 | 3. server/error.js:middleware - express errors 30 | 31 | This is not says if express breaks it more of it a error happens on expresses watch then it will defer to this function. 32 | 33 | ``` javascript 34 | self.app.use(function (err, req, res, next) { 35 | // 1st pull out all relevant information out of err 36 | // 2nd check against any common validations with mongoose 37 | // 3rd start construction all information we can compile for you 38 | // 4th check if the status code is 500 and over then we log the error with our system 39 | // 5th check for production mode and if so then do not send back stack/text information 40 | // 6th send the info we can back to the sure 41 | }) 42 | ``` 43 | 44 | #### How do we log our errors 45 | 46 | `error.log()` 47 | 48 | #### server.error.js:log - system error log 49 | 50 | We log every issue for you now in the database under the `error` collection. In doing that we wanted to give admins a place to view there data instead of just in a log(we still log out the error too). check out the [Dashboard](http://localhost:3000/admin?view=errors). We know that some errors will repeat so we check for the same message seeing as that is our main indicator of what happened. If we find the same one again we will update the count and add a timestamp to the history. With this in place you will now have the ability to add back in the logic we have commented out to allowing you to email yourself when you think its worth knowing about with your own rules on the data. Check it out and let us know your thoughts. -------------------------------------------------------------------------------- /client/modules/header/header.spec.js: -------------------------------------------------------------------------------- 1 | describe('HEADER Testing', function () { 2 | describe('controller', function () { 3 | var authResponse = { 4 | user: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwcm9maWxlIjp7ImdlbmRlciI6Ik1hbGUiLCJsb2NhdGlvbiI6IkludGVybmF0aW9uYWwiLCJ3ZWJzaXRlIjoiZ29vZ2xlLmNvbSIsInBpY3R1cmUiOiIiLCJuYW1lIjoiVGVzdCBVc2VyIn0sInJvbGVzIjpbXSwiZ3JhdmF0YXIiOiJodHRwczovL2dyYXZhdGFyLmNvbS9hdmF0YXIvZDViYjRmZmZmYTZhMzI0MjhjN2UzMTBjMzQxYjRmN2I_cz0yMDAmZD1yZXRybyIsImVtYWlsIjoidGVzdEB1c2VyLmNvbSIsIl9pZCI6IjU3MTdhMmQ1MGI1ZTQ0YWE1ZTU0NjQ4YiIsImlhdCI6MTQ2MTE2NzQ5NSwiZXhwIjoxNDYxMTc0Njk1fQ.tsAiRGB-lUhnD70XXtliNsTzQj3gKLA0a28yTJWoo8c' 5 | } 6 | var UserFactory 7 | var $httpBackend 8 | var HeaderController 9 | 10 | beforeEach(module('app.header')) 11 | beforeEach(module('app.index')) 12 | beforeEach(module('app.user')) 13 | beforeEach(inject(function (_$httpBackend_, $controller, $rootScope, _UserFactory_) { 14 | UserFactory = _UserFactory_ 15 | $httpBackend = _$httpBackend_ 16 | $httpBackend.when('POST', /\/api\/user\/logout/) 17 | .respond(200, '') 18 | $httpBackend.when('GET', /\/api\/user\/authenticate\?noCache=\d+/) 19 | .respond(200, authResponse) 20 | $httpBackend.when('GET', /\/api\/seo\/*/) 21 | .respond(200, {}) 22 | $httpBackend.when('GET', /modules\/core\/[\d\w]+\.view\.html\?noCache=\d+/) 23 | .respond(200, '') 24 | $httpBackend.when('GET', /modules\/index\/[\d\w]+\.view\.html\?noCache=\d+/) 25 | .respond(200, '') 26 | // Authenticate in UserFactory class constructor 27 | $httpBackend.flush() 28 | var $scope = $rootScope.$new() 29 | HeaderController = $controller('HeaderController', { $scope: $scope }) 30 | })) 31 | 32 | it('should exist', function () { 33 | expect(HeaderController).to.exist 34 | }) 35 | 36 | it('vm.logout() should empty vm user factory', function () { 37 | // Filled by authentication in beforeEach 38 | expect(HeaderController.UserFactory).to.not.be.empty 39 | expect(HeaderController.UserFactory).to.equal(UserFactory) 40 | HeaderController.logout() 41 | $httpBackend.flush() 42 | expect(HeaderController.UserFactory).to.be.empty 43 | }) 44 | }) 45 | 46 | this.timeout(500) 47 | 48 | it('should take less than 500ms', function (done) { 49 | setTimeout(done, 300) 50 | }) 51 | 52 | it('should take less than 500ms as well', function (done) { 53 | setTimeout(done, 200) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /documentation/Getting-Started.md: -------------------------------------------------------------------------------- 1 | ### Getting Started 2 | 3 | #### Prerequisites: Option 1 4 | 5 | -   [Download](https://www.mongodb.org/downloads) and Install mongodb - Checkout their manual if you're just starting. 6 | -   [OSX MongoDB](https://docs.mongodb.org/manual/tutorial/install-mongodb-on-os-x/) 7 | -   [Windows Mongodb](https://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/) 8 | -   [Linux Mongodb](https://docs.mongodb.org/manual/administration/install-on-linux/) 9 | -   [Download](http://nodejs.org) and Install Node.js - nodeschool has free node tutorials to get you started. 10 | 11 | #### Prerequisites: Option 2 12 | 13 | Download our repo & run CLI - NOTE: not for windows users. Please use the links above to install 14 | 15 | We have built in all of the installs in our system to help new users or to help people install in cloud envs. 16 | 17 | ``` bash 18 | npm run cli 19 | # select - Mean Stack JS Install Dependencies 20 | # the select - Install MongoDB 21 | # in a new window or tab select - Start Mongod 22 | ``` 23 | #### Start 24 | 25 | The easiest way to get started is to clone the repository: 26 | 27 | ``` bash 28 | # Get the latest snapshot 29 | git clone https://github.com/greenpioneersolutions/meanstackjs.git 30 | 31 | # Change directory 32 | cd meanstackjs 33 | 34 | # Install NPM dependencies 35 | npm install 36 | 37 | # Start up the server 38 | npm start 39 | # or 40 | node index.js 41 | # or 42 | nodemon index.js 43 | ``` 44 | 45 | #### Testing 46 | 47 | Easiest way to start testing your whole system 48 | 49 | ``` bash 50 | npm run cli 51 | # select - Install Selenium Server 52 | # once installed - Start Selenium Server 53 | npm test 54 | ``` 55 | 56 | Note you must have mongodb running and if you dont then 57 | ``` bash 58 | npm run cli 59 | # the select - Install MongoDB 60 | # in a new window or tab select - Start Mongod 61 | ``` -------------------------------------------------------------------------------- /client/modules/user/user.routes.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.user') 6 | .run(appRun) 7 | 8 | appRun.$inject = ['routerHelper'] 9 | /* @ngInject */ 10 | function appRun (routerHelper) { 11 | routerHelper.configureStates(getStates()) 12 | } 13 | 14 | function getStates () { 15 | return [ 16 | { 17 | state: 'signin', 18 | config: { 19 | url: '/signin?redirect', 20 | templateUrl: 'modules/user/signin.view.html', 21 | controller: 'UserController', 22 | controllerAs: 'vm', 23 | resolve: { 24 | loggedout: function (UserFactory) { 25 | return UserFactory.checkLoggedOut() 26 | } 27 | } 28 | } 29 | }, 30 | { 31 | state: 'signup', 32 | config: { 33 | url: '/signup?redirect', 34 | templateUrl: 'modules/user/signup.view.html', 35 | controller: 'UserController', 36 | controllerAs: 'vm', 37 | resolve: { 38 | loggedout: function (UserFactory) { 39 | return UserFactory.checkLoggedOut() 40 | } 41 | } 42 | } 43 | }, 44 | { 45 | state: 'account', 46 | config: { 47 | url: '/account', 48 | templateUrl: 'modules/user/account.view.html', 49 | controller: 'UserController', 50 | controllerAs: 'vm', 51 | resolve: { 52 | loggedin: function (UserFactory) { 53 | return UserFactory.checkLoggedin() 54 | } 55 | } 56 | } 57 | }, 58 | { 59 | state: 'forgot', 60 | config: { 61 | url: '/forgot', 62 | templateUrl: 'modules/user/forgot.view.html', 63 | controller: 'UserController', 64 | controllerAs: 'vm', 65 | resolve: { 66 | loggedin: function (UserFactory) { 67 | return UserFactory.checkLoggedOut() 68 | } 69 | } 70 | } 71 | }, 72 | { 73 | state: 'reset', 74 | config: { 75 | url: '/reset/:token', 76 | templateUrl: 'modules/user/reset.view.html', 77 | controller: 'UserController', 78 | controllerAs: 'vm', 79 | resolve: { 80 | loggedin: function (UserFactory) { 81 | return UserFactory.checkLoggedOut() 82 | } 83 | } 84 | } 85 | } 86 | ] 87 | } 88 | })() 89 | -------------------------------------------------------------------------------- /client/modules/blog/create.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Create Blog Post

6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |

Title is required

15 |

Title must be at least 2 characters long

16 |
17 |
18 |
19 | 20 |
21 | 22 |

Content is required

23 |

Content must be at least 2 characters long

24 |
25 |
26 |
27 |
28 | 29 | Cancel 30 |
31 |
32 |
33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /client/modules/blog/edit.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Edit

6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |

Title is required

15 |

Title must be at least 2 characters long

16 |
17 |
18 |
19 | 20 |
21 | 22 |

Content is required

23 |

Content must be at least 2 characters long

24 |
25 |
26 |
27 |
28 | 29 | Cancel 30 |
31 |
32 |
33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /server/seo.js: -------------------------------------------------------------------------------- 1 | module.exports = Seo 2 | 3 | var pathToRegexp = require('path-to-regexp') 4 | var _ = require('lodash') 5 | var ejs = require('ejs') 6 | 7 | function Seo (self, req, path, cb) { 8 | // ADD AUTH TO ROUTES 9 | var matched = false 10 | if (typeof path === 'function') { 11 | cb = path 12 | path = req.path 13 | } 14 | if (!self.settings.seo) return cb(self.settings.html) 15 | _.forEach(self.settings.seo, function (pathSettings, pathValue) { 16 | var keys = [] 17 | var regexMatch = pathToRegexp(pathValue, keys, { sensitive: false, strict: true, end: true }) 18 | var match = regexMatch.exec(path) 19 | if (match) { 20 | matched = true 21 | var obj = { 22 | query: req.query, 23 | user: req.user || {}, 24 | params: {}, 25 | path: (req.protocol + '://' + req.headers.host + req.path) 26 | } 27 | for (var i = 1; i < match.length; i++) { 28 | obj.params[keys[i - 1].name] = match[i] 29 | } 30 | if (pathSettings.hook) { 31 | pathSettings.hook(self, obj, function (error, data) { 32 | if (error) { 33 | return cb(self.settings.html) 34 | } 35 | if (!data) { 36 | data = obj 37 | } 38 | return cb(_.assign(self.settings.html, compile({ name: self.settings.render.seo.toLowerCase(), options: self.settings.render[self.settings.render.seo.toLowerCase()].options }, pathSettings, data, self))) 39 | }) 40 | } else { 41 | return cb(_.assign(self.settings.html, compile({ name: self.settings.render.seo.toLowerCase(), options: self.settings.render[self.settings.render.seo.toLowerCase()].options }, pathSettings, obj, self))) 42 | } 43 | return false 44 | } 45 | }) 46 | if (!matched) { 47 | return cb(self.settings.html) 48 | } 49 | } 50 | function compile (type, seo, data, self) { 51 | var compiled = {} 52 | _.forEach(seo, function (value, prop) { 53 | if (prop === 'hook') { return } 54 | if (type.name === 'lodash') { 55 | var propTemplate = _.template(value, type.options) 56 | try { 57 | compiled[prop] = propTemplate(data) 58 | } catch (error) { 59 | self.logger.warn(error.message, ' in seo compile lodash') 60 | } 61 | } else if (type.name === 'ejs') { 62 | try { 63 | compiled[prop] = ejs.render(value, data, type.options) 64 | } catch (error) { 65 | self.logger.warn(error.message, ' in seo compile ejs') 66 | } 67 | } 68 | }) 69 | 70 | return compiled 71 | } 72 | -------------------------------------------------------------------------------- /server/routes.js: -------------------------------------------------------------------------------- 1 | module.exports.buildRoutes = routes 2 | 3 | var express = require('express') 4 | var ejs = require('ejs') 5 | var path = require('path') 6 | var seo = require('./seo') 7 | var debug = require('debug')('meanstackjs:routes') 8 | var glob = require('glob') 9 | 10 | function routes (self) { 11 | debug('started createBackendRoutes') 12 | // Dynamic Routes / Manually enabling them . You can change it back to automatic in the settings 13 | // var build = require('buildreq')() 14 | // var mongoose = require('mongoose') 15 | // build.routing(app, mongoose) - if reverting back to automatic 16 | 17 | // self.app.use(self.build.responseMiddleware({mongoose: mongoose})) 18 | // self.build.routing({ 19 | // mongoose: mongoose, 20 | // remove: ['users'], 21 | // middleware: { 22 | // auth: [self.middleware.verify, self.middleware.isAuthenticated] 23 | // } 24 | // }, function (error, data) { 25 | // if (error) self.logger.warn(error) 26 | // _.forEach(data, function (m) { 27 | // debug('Route Built by NPM buildreq:', m.route) 28 | // self.app.use(m.route, m.app) 29 | // }) 30 | // }) 31 | var files = glob.sync('server/modules/**/*.routes.js') 32 | files.forEach(function (router) { 33 | debug('Route : %s', router) 34 | require('../' + router)(self.app, self.middleware, self.mail, self.settings, self.models, self.logger) 35 | }) 36 | self.app.use(express.static(path.join(self.dir, 'client/'), { 37 | maxAge: self.settings.cache.maxAge 38 | })) 39 | self.app.get('/api/seo/*', function (req, res) { 40 | seo(self, req, req.path.replace('/api/seo', ''), function (seoSettings) { 41 | res.send(seoSettings) 42 | }) 43 | }) 44 | self.app.get('/:url(api|images|scripts|styles|components|uploads|modules)/*', function (req, res) { 45 | res.status(400).send({ 46 | error: 'nothing found at ' + req.path 47 | }) 48 | }) 49 | self.app.get('/*', function (req, res, next) { 50 | seo(self, req, function (seoSettings) { 51 | ejs.renderFile(path.join(__dirname, './layout/index.html'), { 52 | html: seoSettings, 53 | googleAnalytics: self.settings.googleAnalytics, 54 | name: self.settings.app.name, 55 | assets: self.app.locals.frontendFilesFinal, 56 | environment: self.environment, 57 | user: req.user ? req.user : {} 58 | }, { 59 | cache: true 60 | }, function (error, str) { 61 | if (error) next(error) 62 | res.send(str) 63 | }) 64 | }) 65 | }) 66 | debug('end createBackendRoutes') 67 | } 68 | -------------------------------------------------------------------------------- /client/modules/user/reset.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 15 | 16 |

Password must be at least 6 characters

17 |

Password must contain a letter, a number, and a symbol

18 |
19 |
20 | 21 | 22 |

Passwords must match

23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /client/modules/admin/messages.view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 10 |
11 |
12 |

Lorem profile dolor sit amet, consectetur adipiscing elit. Duis pharetra varius quam sit amet vulputate. 13 |

Quisque mauris augue, molestie tincidunt condimentum vitae, gravida a libero. Aenean sit amet felis dolor, in sagittis nisi.

14 |
15 |
16 |

Message ipsum dolor sit amet, consectetur adipiscing elit. Duis pharetra varius quam sit amet vulputate. 17 |

Quisque mauris augu.

18 |
19 |
20 |

Lorem settings dolor sit amet, consectetur adipiscing elit. Duis pharetra varius quam sit amet vulputate. 21 |

Quisque mauris augue, molestie.

22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 | 30 | 31 |
32 |
Inbox Messages 3
33 | 34 |
35 | 36 | 54 |
55 |
-------------------------------------------------------------------------------- /server/error.js: -------------------------------------------------------------------------------- 1 | exports.log = log 2 | exports.errorMiddleware = middleware 3 | 4 | var httpStatus = require('http-status-codes') 5 | var debug = require('debug')('meanstackjs:error') 6 | var logger = require('./logger.js').logger 7 | 8 | function log (error, cb) { 9 | if (typeof cb !== 'function') { 10 | cb = function () {} 11 | } 12 | if (!(error instanceof Error)) { 13 | error = new Error(error) 14 | } 15 | logger.error(error.message, error) 16 | } 17 | 18 | function jsonStringify (obj) { 19 | return JSON.stringify(obj, null, 2) 20 | } 21 | 22 | function middleware (self) { 23 | self.app.use(function (error, req, res, next) { 24 | var code = typeof error.status === 'number' ? error.status : 500 25 | var message = error.message || error.msg 26 | var type = 'express' 27 | var ip = req.ip || req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress 28 | 29 | if (error.name === 'ValidationError') { 30 | code = 400 31 | message = 'Validation Error' 32 | type = 'mongo' 33 | } 34 | if (error.name === 'CastError') { 35 | code = 400 36 | message = 'Invalid Cast' 37 | type = 'mongo' 38 | } 39 | if (error.message === 'MongoError') { 40 | code = 400 41 | if (error.code === 11000) message = 'Duplicate key error ' 42 | else message = 'Database Error' 43 | type = 'mongo' 44 | } 45 | 46 | var text = '\n=== EXCEPTION ===\n \n' + 47 | 'Message:\n' + 48 | message + '\n\n' + 49 | 'Code:\n' + code + '\n \n' + 50 | 'User:\n' + (req.user ? req.user.email : 'no user info') + '\n \n' + 51 | 'IP Address:\n' + (ip || 'no IP') + '\n \n' + 52 | 'User-Agent:\n' + jsonStringify(req.headers['user-agent']) + '\n \n' + 53 | 'Route:\n' + req.method + '-' + req.url + '\n \n' + 54 | 'Headers:\n' + '\n' + jsonStringify(req.headers) + '\n \n' + 55 | 'Params:\n' + '\n' + jsonStringify(req.params) + '\n \n' + 56 | 'Body:\n' + '\n' + jsonStringify(req.body) + '\n \n' + 57 | 'Session:\n' + '\n' + jsonStringify(req.session) + '\n \n' + 58 | 'Stack:\n' + error.stack + '\n' 59 | 60 | res.status(code) 61 | 62 | if (code >= 500) { 63 | error.type = type 64 | error.stack = text 65 | log(error) 66 | } 67 | 68 | var renderData = { 69 | text: '', 70 | message: message, 71 | code: code, 72 | title: code + ' ' + httpStatus.getStatusText(code) 73 | } 74 | if (self.environment !== 'production') { 75 | renderData.text = text 76 | } 77 | debug('error message & code:' + message + ' - ' + code) 78 | return res.send(renderData) 79 | }) 80 | } 81 | -------------------------------------------------------------------------------- /commands/template/client/create.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Create <%= Name %>

6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |

Title is required

15 |

Title must be at least 2 characters long

16 |
17 |
18 |
19 | 20 |
21 | 22 |

Content is required

23 |

Content must be at least 2 characters long

24 |
25 |
26 |
27 |
28 | 29 | Cancel 30 |
31 |
32 |
33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /commands/template/client/edit.view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Edit <%= Name %>

6 |
7 |
8 |
9 |
10 |
11 | 12 |
13 | 14 |

Title is required

15 |

Title must be at least 2 characters long

16 |
17 |
18 |
19 | 20 |
21 | 22 |

Content is required

23 |

Content must be at least 2 characters long

24 |
25 |
26 |
27 |
28 | 29 | Cancel 30 |
31 |
32 |
33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /client/modules/user/user.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.user', []) 6 | .controller('UserController', UserController) 7 | 8 | UserController.$inject = ['$scope', '$http', '$cookies', 'config', '$state', '$timeout', 'UserFactory', 'logger', 'Upload', '$stateParams'] 9 | 10 | /* @ngInject */ 11 | function UserController ($scope, $http, $cookies, config, $state, $timeout, UserFactory, logger, Upload, $stateParams) { 12 | var vm = this 13 | vm.resetCred = vm.editProfile = vm.loginCred = {} 14 | vm.UserFactory = UserFactory 15 | vm.refreshApiToken = function () { 16 | UserFactory.resetApiToken() 17 | } 18 | vm.find = function () { 19 | vm.editProfile = angular.copy(UserFactory.user) 20 | } 21 | vm.login = function (validated) { 22 | if (validated) UserFactory.login(vm) 23 | else logger.warning('Data not valid', vm, 'Login Validation') 24 | } 25 | vm.signup = function (validated) { 26 | if (validated) UserFactory.signup(vm) 27 | else logger.warning('Data not valid', vm, 'Signup Validation') 28 | } 29 | vm.forgot = function (validated) { 30 | if (validated) UserFactory.forgot(vm) 31 | else logger.warning('Data not valid', vm, 'Forgot Password Validation') 32 | } 33 | vm.resetTokenCheck = function () { 34 | UserFactory.resetTokenCheck(vm) 35 | } 36 | vm.reset = function (validated) { 37 | if (validated) UserFactory.resetpassword(vm) 38 | else logger.warning('Data not valid', vm, 'Reset Password Validation') 39 | } 40 | vm.resetToken = $stateParams.token 41 | vm.update = function (validated) { 42 | if (validated) UserFactory.update(vm) 43 | else logger.warning('Data not valid', vm, 'Profile Validation') 44 | } 45 | vm.upload = function (file) { 46 | Upload.upload({ 47 | url: '/api/photos/upload', 48 | data: { file: file, 'user': UserFactory } 49 | }).then(function (resp) { 50 | console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data) 51 | }, function (resp) { 52 | console.log('Error status: ' + resp.status) 53 | }, function (evt) { 54 | var progressPercentage = parseInt(100.0 * evt.loaded / evt.total) // eslint-disable-line 55 | console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name) 56 | }) 57 | } 58 | activate() 59 | 60 | function activate () { 61 | // Handle redirects 62 | $scope.$on('$stateChangeSuccess', function (ev, toState, toParams, fromState, fromParams) { 63 | var redirectPath = $state.href(fromState.name, fromParams) 64 | $cookies.put('redirect', redirectPath) 65 | }) 66 | } 67 | } 68 | })() 69 | -------------------------------------------------------------------------------- /commands/template/server/controller.js: -------------------------------------------------------------------------------- 1 | exports.get<%= Name %> = get<%= Name %> 2 | exports.delete<%= Name %> = delete<%= Name %> 3 | exports.post<%= Name %> = post<%= Name %> 4 | exports.put<%= Name %> = put<%= Name %> 5 | exports.get<%= Name %>ById = get<%= Name %>ById 6 | exports.param<%= Name %> = param<%= Name %> 7 | exports.on<%= Name %> = on<%= Name %> 8 | 9 | var auto = require('run-auto') 10 | var mongoose = require('mongoose') 11 | var <%= name %>s = mongoose.model('<%= name %>') 12 | var _ = require('lodash') 13 | //var logger = require('./../../logger.js').logger 14 | 15 | function get<%= Name %> (req, res, next) { 16 | auto({ 17 | <%= name %>s: function (cb) { 18 | <%= name %>s 19 | .find() 20 | .exec(cb) 21 | } 22 | }, function (error, results) { 23 | if (error) return next(error) 24 | return res.status(200).send(results.<%= name %>s) 25 | }) 26 | } 27 | 28 | function delete<%= Name %> (req, res, next) { 29 | req.<%= name %>.remove(function () { 30 | res.status(204).send() 31 | }) 32 | } 33 | 34 | function post<%= Name %> (req, res, next) { 35 | // req.assert('name', 'The name cannot be blank').notEmpty() 36 | 37 | var errors = req.validationErrors() 38 | if (errors) { 39 | return res.status(400).send({ 40 | success: false, 41 | message: errors[0].message, 42 | redirect: '/' 43 | }) 44 | } 45 | req.body.user = req.user._id 46 | <%= name %>s.create(req.body, function (error, data) { 47 | if (error) return next(error) 48 | return res.status(201).send(data) 49 | }) 50 | } 51 | 52 | function put<%= Name %> (req, res, next) { 53 | req.<%= name %> = _.assign(req.<%= name %>, req.body) 54 | req.<%= name %>.save(function (error) { 55 | if (error) return next(error) 56 | return res.status(200).send(req.<%= name %>) 57 | }) 58 | } 59 | 60 | 61 | function get<%= Name %>ById (req, res, next) { 62 | res.send(req.<%= name %>) 63 | } 64 | 65 | function param<%= Name %> (req, res, next, id) { 66 | req.assert('<%= name %>Id', 'Your <%= Name %> ID cannot be blank').notEmpty() 67 | req.assert('<%= name %>Id', 'Your <%= Name %> ID has to be a real id').isMongoId() 68 | 69 | var errors = req.validationErrors() 70 | if (errors) { 71 | return res.status(400).send({ 72 | success: false, 73 | message: errors[0].message, 74 | redirect: '/' 75 | }) 76 | } 77 | auto({ 78 | <%= name %>: function (cb) { 79 | <%= name %>s 80 | .findOne({_id: id}) 81 | .exec(cb) 82 | } 83 | }, function (error, results) { 84 | if (error) return next(error) 85 | req.<%= name %> = results.<%= name %> 86 | next() 87 | }) 88 | } 89 | 90 | function on<%= Name %> (io, socket) { 91 | return function (msg) { 92 | io.emit('<%= name %>', msg) 93 | } 94 | } -------------------------------------------------------------------------------- /client/modules/blog/blog.controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.blog', []) 6 | .controller('BlogController', BlogController) 7 | 8 | BlogController.$inject = ['$http', '$stateParams', 'BlogFactory', 'logger', '$location', 'UserFactory'] 9 | /* @ngInject */ 10 | function BlogController ($http, $stateParams, BlogFactory, logger, $location, UserFactory) { 11 | var vm = this 12 | vm.title = 'System' 13 | vm.blog = {} 14 | vm.UserFactory = UserFactory 15 | activate() 16 | vm.create = function (validated) { 17 | if (!validated) { 18 | logger.warning('Data not valid', vm, 'Create Blog Post Validation') 19 | return 20 | } 21 | var blog = new BlogFactory(vm.blog) 22 | blog.user = vm.UserFactory.user 23 | blog.$save(function (response) { 24 | vm.blog = response 25 | // window.location.href 26 | $location.url('/blog/list') 27 | }, function (error) { 28 | logger.error(error.data.message, error, 'Blog') 29 | }) 30 | } 31 | vm.find = function () { 32 | BlogFactory.get({ 33 | id: $stateParams.id 34 | }, function (success) { 35 | vm.blog = success 36 | }, function (error) { 37 | logger.error(error.data.message, error, 'Blog') 38 | }) 39 | } 40 | vm.list = function () { 41 | BlogFactory.get(function (success) { 42 | vm.blogs = success.blogs 43 | vm.count = success.count 44 | }, function (error) { 45 | logger.error(error.data.message, error, 'Blog') 46 | }) 47 | } 48 | vm.update = function (validated) { 49 | if (!validated) { 50 | logger.warning('Data not valid', vm, 'Edit Blog Post Validation') 51 | return 52 | } 53 | BlogFactory.update({ 54 | id: $stateParams.id 55 | }, vm.blog, 56 | function (success) { 57 | $location.url('/blog/view/' + $stateParams.id) 58 | }, 59 | function (error) { 60 | logger.error(error.data.message, error, 'Blog') 61 | }) 62 | } 63 | vm.delete = function (blogId) { 64 | // Disable confirm for testing purposes 65 | var deleteConfirm = true 66 | // var deleteConfirm = confirm('Are you sure you want to delete this blog?') // eslint-disable-line 67 | if (deleteConfirm === true) { 68 | BlogFactory.remove({ 69 | id: blogId 70 | }, 71 | function (success) { 72 | for (var i in vm.blogs) { 73 | if (vm.blogs[i]._id === blogId) { 74 | vm.blogs.splice(i, 1) 75 | } 76 | } 77 | }, 78 | function (error) { 79 | logger.error(error.data.message, error, 'Blog') 80 | }) 81 | } 82 | } 83 | function activate () { 84 | logger.info('Activated Blog View') 85 | } 86 | } 87 | })() 88 | -------------------------------------------------------------------------------- /tests/unit/karma.test.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | var path = require('path') 3 | var _ = require('lodash') 4 | var settings = require('../../configs/settings.js').get() 5 | var fs = require('fs') 6 | var dependencies = settings.assets.js 7 | var dependencyFiles = _.map(dependencies, function (dependency) { 8 | if (fs.existsSync(path.resolve('./node_modules/' + dependency))) { 9 | return path.resolve('./client/components/' + dependency).toString() 10 | } else { 11 | return path.resolve('./client/' + dependency).toString() 12 | } 13 | }) 14 | var clientPath = '../../client' 15 | var srcFiles = [ 16 | clientPath + '/modules/**/*.module.js', 17 | clientPath + '/modules/**/*.js' 18 | ] 19 | var files = dependencyFiles.reverse().concat(srcFiles) 20 | 21 | var configuration = { 22 | customLaunchers: { 23 | Chrome_travis_ci: { 24 | base: 'Chrome', 25 | flags: ['--no-sandbox'] 26 | } 27 | }, 28 | // base path that will be used to resolve all patterns (eg. files, exclude) 29 | basePath: './', 30 | 31 | // frameworks to use 32 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 33 | frameworks: ['mocha', 'chai'], 34 | 35 | // list of files / patterns to load in the browser 36 | files: files, 37 | 38 | // list of files to exclude 39 | exclude: [], 40 | 41 | // preprocess matching files before serving them to the browser 42 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 43 | preprocessors: { 44 | }, 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['progress'], 50 | 51 | // web server port 52 | port: 9876, 53 | 54 | // enable / disable colors in the output (reporters and logs) 55 | colors: true, 56 | 57 | // level of logging 58 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 59 | logLevel: config.LOG_INFO, 60 | 61 | // enable / disable watching file and executing tests whenever any file changes 62 | autoWatch: true, 63 | 64 | // start these browsers 65 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 66 | browsers: ['Chrome'], 67 | 68 | // Continuous Integration mode 69 | // if true, Karma captures browsers, runs the tests and exits 70 | singleRun: true, 71 | 72 | // Concurrency level 73 | // how many browser should be started simultaneous 74 | concurrency: Infinity, 75 | 76 | plugins: [ 77 | 'karma-mocha', 78 | 'karma-chai', 79 | 'karma-chrome-launcher' 80 | ] 81 | } 82 | if (process.env.TRAVIS) { 83 | configuration.browsers = ['Chrome_travis_ci'] 84 | } 85 | config.set(configuration) 86 | } 87 | -------------------------------------------------------------------------------- /commands/template/client/controller.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 'use strict' 3 | 4 | angular 5 | .module('app.<%= name %>', []) 6 | .controller('<%= Name %>Controller', <%= Name %>Controller) 7 | 8 | <%= Name %>Controller.$inject = ['$http', '$stateParams', '<%= Name %>Factory', 'logger', '$location', 'UserFactory'] 9 | /* @ngInject */ 10 | function <%= Name %>Controller ($http, $stateParams, <%= Name %>Factory, logger, $location, UserFactory) { 11 | var vm = this 12 | vm.title = '<%= name %>' 13 | vm.<%= name %> = {} 14 | vm.UserFactory = UserFactory 15 | activate() 16 | 17 | vm.create = function (validated) { 18 | if (!validated) { 19 | logger.warning('Data not valid', vm, 'Create <%= Name %> Validation') 20 | return 21 | } 22 | var <%= name %> = new <%= Name %>Factory(vm.<%= name %>) 23 | <%= name %>.user = vm.UserFactory.user 24 | <%= name %>.$save(function (response) { 25 | vm.<%= name %> = response 26 | // window.location.href 27 | $location.url('/<%= name %>/list') 28 | }, function (error) { 29 | logger.error(error) 30 | }) 31 | } 32 | vm.find = function () { 33 | <%= Name %>Factory.get({ 34 | id: $stateParams.id 35 | }, function (success) { 36 | vm.<%= name %> = success 37 | }, function (error) { 38 | logger.error(error) 39 | }) 40 | } 41 | vm.list = function () { 42 | <%= Name %>Factory.query(function (success) { 43 | vm.<%= name %>s = success 44 | }, function (error) { 45 | logger.error(error) 46 | }) 47 | } 48 | vm.update = function (validated) { 49 | if (!validated) { 50 | logger.warning('Data not valid', vm, 'Edit <%= Name %> Post Validation') 51 | return 52 | } 53 | <%= Name %>Factory.update({ 54 | id: $stateParams.id 55 | }, vm.<%= name %>, 56 | function (success) { 57 | $location.url('/<%= name %>/view/' + $stateParams.id) 58 | }, 59 | function (error) { 60 | logger.error(error) 61 | }) 62 | } 63 | vm.delete = function (<%= name %>Id) { 64 | // Confirm disabled for testing purposes 65 | var deleteConfirm = true 66 | // var deleteConfirm = confirm('Are you sure you want to delete this <%= name %>?') // eslint-disable-line 67 | if (deleteConfirm === true) { 68 | <%= Name %>Factory.remove({ 69 | id: <%= name %>Id 70 | }, 71 | function (success) { 72 | for (var i in vm.<%= name %>s) { 73 | if (vm.<%= name %>s[i]._id === <%= name %>Id) { 74 | vm.<%= name %>s.splice(i, 1) 75 | } 76 | } 77 | }, 78 | function (error) { 79 | logger.error(error) 80 | }) 81 | } 82 | } 83 | function activate () { 84 | logger.info('Activated <%= Name %> View') 85 | } 86 | } 87 | })() 88 | -------------------------------------------------------------------------------- /client/modules/index/index.style.css: -------------------------------------------------------------------------------- 1 | /* 2 | normal .css files are supported and will be agregated with other styles. 3 | */ 4 | .bs-calltoaction{ 5 | position: relative; 6 | width:auto; 7 | padding: 15px 25px; 8 | border: 1px solid black; 9 | margin-top: 10px; 10 | margin-bottom: 10px; 11 | border-radius: 5px; 12 | } 13 | 14 | .bs-calltoaction > .row{ 15 | display:table; 16 | width: calc(100% + 30px); 17 | } 18 | 19 | .bs-calltoaction > .row > [class^="col-"], 20 | .bs-calltoaction > .row > [class*=" col-"]{ 21 | float:none; 22 | display:table-cell; 23 | vertical-align:middle; 24 | } 25 | 26 | .cta-contents{ 27 | padding-top: 10px; 28 | padding-bottom: 10px; 29 | } 30 | 31 | .cta-title{ 32 | margin: 0 auto 15px; 33 | padding: 0; 34 | } 35 | 36 | .cta-desc{ 37 | padding: 0; 38 | } 39 | 40 | .cta-desc p:last-child{ 41 | margin-bottom: 0; 42 | } 43 | 44 | .cta-button{ 45 | padding-top: 10px; 46 | padding-bottom: 10px; 47 | } 48 | 49 | @media (max-width: 991px){ 50 | .bs-calltoaction > .row{ 51 | display:block; 52 | width: auto; 53 | } 54 | 55 | .bs-calltoaction > .row > [class^="col-"], 56 | .bs-calltoaction > .row > [class*=" col-"]{ 57 | float:none; 58 | display:block; 59 | vertical-align:middle; 60 | position: relative; 61 | } 62 | 63 | .cta-contents{ 64 | text-align: center; 65 | } 66 | } 67 | 68 | 69 | 70 | .bs-calltoaction.bs-calltoaction-default{ 71 | color: #333; 72 | background-color: #fff; 73 | border-color: #ccc; 74 | } 75 | 76 | .bs-calltoaction.bs-calltoaction-primary{ 77 | color: #fff; 78 | background-color: #337ab7; 79 | border-color: #2e6da4; 80 | } 81 | 82 | .bs-calltoaction.bs-calltoaction-info{ 83 | color: #fff; 84 | background-color: #5bc0de; 85 | border-color: #46b8da; 86 | } 87 | 88 | .bs-calltoaction.bs-calltoaction-success{ 89 | color: #fff; 90 | background-color: #5cb85c; 91 | border-color: #4cae4c; 92 | } 93 | 94 | .bs-calltoaction.bs-calltoaction-warning{ 95 | color: #fff; 96 | background-color: #f0ad4e; 97 | border-color: #eea236; 98 | } 99 | 100 | .bs-calltoaction.bs-calltoaction-danger{ 101 | color: #fff; 102 | background-color: #d9534f; 103 | border-color: #d43f3a; 104 | } 105 | 106 | .bs-calltoaction.bs-calltoaction-primary .cta-button .btn, 107 | .bs-calltoaction.bs-calltoaction-info .cta-button .btn, 108 | .bs-calltoaction.bs-calltoaction-success .cta-button .btn, 109 | .bs-calltoaction.bs-calltoaction-warning .cta-button .btn, 110 | .bs-calltoaction.bs-calltoaction-danger .cta-button .btn{ 111 | border-color:#fff; 112 | } 113 | 114 | .cta-title-white{ 115 | color:#FFF; 116 | } -------------------------------------------------------------------------------- /documentation/Development-Document.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Mean 4 | 5 | Mean Stack Server File 6 | 7 | **Parameters** 8 | 9 | - `opts` **[Object][1]** the options passed to create the server 10 | - `done` **[Function][2]** the callback function 11 | MIT Licensed 12 | 13 | ## self 14 | 15 | self context to be used through out the application 16 | 17 | ### dir 18 | 19 | stores the root directory at dir 20 | 21 | ### opts 22 | 23 | stores the options pass in to the server 24 | 25 | ### run 26 | 27 | stores the run function incase you need to spin up any other servers 28 | 29 | ### logger 30 | 31 | creates the logging throught the entire app 32 | 33 | ### environment 34 | 35 | gets & store the current environment 36 | 37 | ### settings 38 | 39 | gets & store the current settings based off of the environment 40 | 41 | ### port 42 | 43 | sets the port based on the options or settings 44 | 45 | ### middleware 46 | 47 | sets up all middleware & placed after db connect to give middleware access 48 | 49 | ### mail 50 | 51 | sets up mailer after db connect to give it access 52 | 53 | ## mongoDB 54 | 55 | Connect to MongoDb & Register mongoose schemas 56 | 57 | ## registerSystemInfo 58 | 59 | setupRegister > Used to gather all modules to gether and to register them properly 60 | 61 | ## configMiddleware 62 | 63 | setupExpressConfigs > Used to set up expressjs initially, middleware & passport. 64 | 65 | ## passport 66 | 67 | setupAuthentication > Used to set up passport authentication & sessions 68 | 69 | ## securityMiddleware 70 | 71 | setupExpressSecurity > Used to set up helmet, hpp, cors & content length. 72 | 73 | ## headersMiddleware 74 | 75 | setupExpressHeaders > Used to set up the headers that go out on every route. 76 | 77 | ## loggerMiddleware 78 | 79 | setupExpressLogger > Used to set up our morgan logger & debug statements on all routes. 80 | 81 | ## setupTools 82 | 83 | setupTools > Used to set up every tool in the tools directory. 84 | 85 | ## buildRoutes 86 | 87 | setupStaticRoutes > Used to set up all system static routes including the main '/\*' route with ejs templating. 88 | 89 | ## errorMiddleware 90 | 91 | errorMiddleware > Used to set up our customer error handler in the server folder. NOTE: This goes after routes because we do not want it potentally default to express error handler 92 | 93 | ## maxCDN 94 | 95 | maxCDN - **_ OPTIONAL _** > Used to purge the max cdn cache of the file. We Support MAXCDN 96 | 97 | ## auto 98 | 99 | auto - connectMongoDb : server > Used to finsh the final set up of the server. at the same time we start connecting to mongo and turning on the server. 100 | 101 | ## SocketIO 102 | 103 | Mean Stack SocketIO Server File 104 | 105 | **Parameters** 106 | 107 | - `opts` **[Object][1]** the options passed to create the server 108 | - `done` **[Function][2]** the callback function 109 | MIT Licensed 110 | 111 | [1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 112 | 113 | [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function 114 | -------------------------------------------------------------------------------- /server/middleware.js: -------------------------------------------------------------------------------- 1 | exports.checkAuthenticated = checkAuthenticated 2 | exports.isAuthenticated = isAuthenticated 3 | exports.isAuthorized = isAuthorized 4 | exports.hasRole = hasRole 5 | exports.isAdmin = isAdmin 6 | 7 | var _ = require('lodash') 8 | var debug = require('debug')('meanstackjs:middleware') 9 | var tokenAPI = require('./token.js') 10 | 11 | function checkAuthenticated (req, cb) { 12 | debug('middleware: checkAuthenticated') 13 | var token = req.headers.authorization || req.query.token || req.body.token // || req.headers['x-access-token'] 14 | if (req.isAuthenticated()) { 15 | return cb() 16 | } else if (token) { 17 | tokenAPI.checkKey(token, function (error, user) { 18 | if (error) return cb(error) 19 | req.user = user 20 | return cb() 21 | }) 22 | } else { 23 | return cb({ 24 | success: false, 25 | message: 'User needs to authenticated' 26 | }) 27 | } 28 | } 29 | 30 | function isAuthenticated (req, res, next) { 31 | debug('middleware: isAuthenticated') 32 | checkAuthenticated(req, function (error) { 33 | if (error) return res.status(401).send(error) 34 | return next() 35 | }) 36 | } 37 | 38 | function isAuthorized (name, extra) { 39 | return function (req, res, next) { 40 | debug('middleware: isAuthorized') 41 | checkAuthenticated(req, function (error) { 42 | if (error) return res.status(401).send(error) 43 | var user 44 | var reqName = req[name] 45 | if (extra) { 46 | var reqExtra = reqName[extra] 47 | reqExtra && reqExtra.user && (user = reqExtra.user) 48 | } else { 49 | user = reqName.user 50 | } 51 | if (req.user) { 52 | if (user._id.toString() !== req.user._id.toString()) { 53 | debug('middleware: is Not Authorized') 54 | return next({ 55 | status: 401, 56 | message: 'User is not Authorized' 57 | }) 58 | } else { 59 | debug('middleware: isAuthenticated') 60 | return next() 61 | } 62 | } else { 63 | debug('middleware: is Not Authorized ') 64 | return res.status(401).send({ 65 | success: false, 66 | message: 'User needs to re-authenticated' 67 | }) 68 | } 69 | }) 70 | } 71 | } 72 | 73 | function hasRole (role) { 74 | return function (req, res, next) { 75 | debug('middleware: hasRole') 76 | checkAuthenticated(req, function (error) { 77 | if (error) return res.status(401).send(error) 78 | if (req.user) { 79 | if (_.includes(req.user.roles, role)) { 80 | return next() 81 | } 82 | } 83 | return res.status(403).send({ 84 | success: false, 85 | message: 'Forbidden' 86 | }) 87 | }) 88 | } 89 | } 90 | 91 | function isAdmin (req, res, next) { 92 | debug('middleware: isAdmin') 93 | checkAuthenticated(req, function (error) { 94 | if (error) return res.status(401).send(error) 95 | if (req.user) { 96 | if (_.includes(req.user.roles, 'admin')) { 97 | return next() 98 | } 99 | } 100 | return res.status(401).send('User is not authorized') 101 | }) 102 | } 103 | --------------------------------------------------------------------------------