diff --git a/Gruntfile.js b/Gruntfile.js index 6991993..30f82ff 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -34,6 +34,7 @@ module.exports = function (grunt) { //Connect proxy to route requests to localhost:8181/api grunt.loadNpmTasks('grunt-connect-proxy'); + grunt.loadNpmTasks('intern'); require('json-proxy').initialize({}); require('load-grunt-tasks')(grunt); require('time-grunt')(grunt); @@ -90,7 +91,10 @@ module.exports = function (grunt) { // Change this to '0.0.0.0' to access the server from outside. hostname: '127.0.0.1', livereload: 35729, - base: ['.tmp', '<%= yeoman.app %>'] + base: ['.tmp', '<%= yeoman.app %>'], + onCreateServer: function(server, connect, options) { + console.warn('onCreateServer', options); + } }, livereload: { options: { @@ -607,6 +611,16 @@ module.exports = function (grunt) { 'test/routes/*-spec.js' ] } + }, + intern: { + test: { + options: { + runType: 'client', + config: 'test/intern.conf', + reporters: [ 'console' ], + suites: [] + } + } } }; diff --git a/app/scripts/controllers/login.coffee b/app/scripts/controllers/login.coffee index f4e70a2..da3337a 100644 --- a/app/scripts/controllers/login.coffee +++ b/app/scripts/controllers/login.coffee @@ -48,15 +48,7 @@ angular.module('angularCmsApp').controller 'LoginCtrl', ($scope, $rootScope, $co ### $scope.logout = (user) -> - - #Clear cookie - $cookieStore.put('App.session', null) - - #Clear session - $rootScope.App.session = null - - #Change location - $rootScope.App.location.path($rootScope.App.logout.redirect) + cmsAuthService.logout(user) #Controller name diff --git a/app/scripts/controllers/media.coffee b/app/scripts/controllers/media.coffee index 38c1beb..87e390d 100644 --- a/app/scripts/controllers/media.coffee +++ b/app/scripts/controllers/media.coffee @@ -4,17 +4,17 @@ angular.module('angularCmsApp').controller 'MediaCtrl', ($scope, $http, DataServ $scope.uploads = [] $scope.getUploads = () -> - $http.get('/api/upload').success((data)-> - $scope.uploads = data + DataService.fetch('uploads').then((res)-> + $scope.uploads = res.data ) $ -> $("#fileupload").fileupload( dataType: 'json' - dropZone: $('.uploader-dropzone') + dropZone: $('.dropzone') add: (e, data) -> console.log(e, data) - + data.url = '/api/upload' data.context = $('

').text('Uploading...').appendTo(document.body) data.submit() @@ -25,7 +25,7 @@ angular.module('angularCmsApp').controller 'MediaCtrl', ($scope, $http, DataServ $.each data.result.files, (index, file) -> $("

").text(file.name).appendTo document.body ) - + $scope.uploader = { files: [] }; diff --git a/app/scripts/controllers/register.coffee b/app/scripts/controllers/register.coffee index a243883..74647b5 100644 --- a/app/scripts/controllers/register.coffee +++ b/app/scripts/controllers/register.coffee @@ -1,6 +1,6 @@ 'use strict' -angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $location, $log, cmsAuthService, cmsSessionService, cmsNotify) -> +angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $log, cmsAuthService) -> $scope.awesomeThings = [ 'HTML5 Boilerplate' 'AngularJS' @@ -21,4 +21,5 @@ angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $location, $ #Handle registering a user $scope.register = (user)-> $log.info('register', user) + cmsAuthService.register(user) diff --git a/app/scripts/controllers/users.coffee b/app/scripts/controllers/users.coffee index df8166d..3cf7261 100644 --- a/app/scripts/controllers/users.coffee +++ b/app/scripts/controllers/users.coffee @@ -55,11 +55,10 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> delete user.password if user.password user.updated_at = new Date() DataService.save('users', user).then((data) -> + $('#user-modal').modal('hide') $scope.getUsers() $scope.users.push(user) unless user._id $scope.user = {} - console.log(data) - $('#user-modal').modal('hide') ) ) diff --git a/app/scripts/directives/cmsuploader.coffee b/app/scripts/directives/cmsuploader.coffee index b121895..1584a78 100644 --- a/app/scripts/directives/cmsuploader.coffee +++ b/app/scripts/directives/cmsuploader.coffee @@ -3,7 +3,7 @@ @name angularCmsApp.directive:cmsUploader @element div @function -@description +@description This is an example uploader. ### 'use strict' @@ -56,7 +56,7 @@ angular.module('angularCmsApp').directive 'cmsUploader', -> xhr.onload = () -> console.log('Upload complete') - xhr.open('POST', '/api/v2/upload', true) + xhr.open('POST', $attrs.action, true) xhr.send(form) console.log('Upload ', file) diff --git a/app/scripts/services/cmsauthservice.coffee b/app/scripts/services/cmsauthservice.coffee index 8290b73..13fc5e7 100644 --- a/app/scripts/services/cmsauthservice.coffee +++ b/app/scripts/services/cmsauthservice.coffee @@ -31,9 +31,11 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo register - I handle register a user. ### register: (user) -> - $http.post(@endpoint + "/register", user).then( + $log.info('trying to register', user); + return $http.post(@endpoint + "/register", user).then( (res)=> - @authorize(res.data) + $log.info(res); + return @authorize(res.data) , (err) -> $log.error(err) cmsNotify( '.message', 'danger', 'Error!', err.data.message, 4000) @@ -45,7 +47,7 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo ### logout: (user) -> #Clear cookie - cmsSessionService.logout(null) + cmsSessionService.setUserAuthenticated(null) $rootScope.apply(()-> $location.reload() ) @@ -59,7 +61,7 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo #Set user session session = - user: res.data.result + user: res.data authorized: true #Set user cookie @@ -68,6 +70,8 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo #Set session on scope $rootScope.App.session = session + $log.info('login-result', res) + #Change location $rootScope.App.location.path('/dashboard') , (err)-> diff --git a/app/views/media.html b/app/views/media.html index ca0e25f..46cdee4 100755 --- a/app/views/media.html +++ b/app/views/media.html @@ -2,14 +2,14 @@

Media


- @@ -18,6 +18,7 @@

Media

  • +
    $scope.uploads: {{uploads | json }}
    diff --git a/config/config.json b/config/config.json index ee1081f..7fff9b2 100644 --- a/config/config.json +++ b/config/config.json @@ -20,10 +20,10 @@ "hostname": "localhost", "port": 5001 }, - "staticDir": "/dist", - "publicDir": "/app", - "uploadsTmpDir": "/.tmp", - "uploadsDestDir": "/www/cms-content/uploads", + "staticDir": "www", + "publicDir": "www", + "uploadsTmpDir": ".tmp", + "uploadsDestDir": "www/cms-content/uploads", "uploadsUrl": ":8181/cms-content/", "logFormat": "[:date] - [:method] - :url - :status - :response-time ms" } diff --git a/package.json b/package.json index b0ff62f..7569e87 100755 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "logfmt": "~0.18.1", "markdown": "~0.5.0", "method-override": "~1.0.0", - "mongodb": "*", + "mongodb": "^1.4.23", "mongoose": "^3.8.20", "passport": "^0.2.1", "passport-facebook": "^1.0.3", @@ -59,7 +59,8 @@ "promised-io": "~0.3.4", "q": "^1.1.2", "request": "~2.34.0", - "socket.io": "~0.9.16" + "socket.io": "~0.9.16", + "websocket": "^1.0.14" }, "devDependencies": { "chai": "^1.10.0", @@ -100,6 +101,7 @@ "gulp-ngmin": "^0.3.0", "gulp-protractor": "0.0.11", "gulp-uglify": "^1.0.2", + "intern": "^2.2.2", "jasmine-core": "^2.1.2", "jasmine-node": "~1.11.0", "jasmine-reporters": "^1.0.1", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 06ae36b..554f0d5 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -3,23 +3,20 @@ var bodyParser = require( 'body-parser' ), util = require('util'), User = require( './models/user' ), session = require( 'express-session' ), - crypto = require( 'crypto' ); + crypto = require( 'crypto'), + bcrypt = require( 'bcrypt-nodejs' ); -var bcrypt = require( 'bcrypt-nodejs' ); - -module.exports = function (config, app) { +var cmsAuth = function (config, app) { console.warn( 'cms-auth' ); - mongoose.connect( config.mongodb ); + //### hashPassword //Hash password using basic sha1 hash. var hashPassword = function (pass, salt) { - var p = bcrypt.hashSync(pass); - - return p; + return bcrypt.hashSync(pass); }; var cmsAuth = { @@ -39,20 +36,20 @@ module.exports = function (config, app) { query.username = req.body.email; } query.password = hashPassword( req.body.password, query.username ); + console.warn('trying to login', query); User.findOne( {username: query.username}, function (err, data) { if (err) { - res.jsonp( 400, err ); + return res.jsonp( 400, err ); } - try { if (data && bcrypt.compareSync(req.body.password, data.password)) { req.session.user = data; - res.jsonp( 200, data ); + return res.json( 200, data ); } else { - res.jsonp( 404, {message: 'Wrong username/password!'} ); + return res.json( 404, {message: 'Wrong username/password!'} ); } } catch (error) { - res.jsonp( 404, {message: error} ); + return res.json( 404, {message: error} ); } } ); }, @@ -70,37 +67,39 @@ module.exports = function (config, app) { data.username = req.body.username; } if (req.body.email) { - data.username = req.body.email; + data.email = req.body.email; } + data.password = hashPassword( req.body.password, data.username ); data.created_at = new Date(); data.updated_at = new Date(); data.active = false; data.groups = ['public']; - var user = new User( data ); + console.warn('trying to register', data); + + //Try and find user User.find( {username: data.username}, function (err, u) { - console.log(err, util.inspect(u, {colors: true})); - + console.log( 'found user', err, util.inspect(u, {colors: true})); + var user = new User( data ); if(err){ - res.json( 400, {message: 'Problem registering!'} ); - } - - if (u.length > 0) { - res.json( 400, {message: 'Username already exists!'} ); + res.jsonp( 400, {message: 'Problem registering!'} ); } - if(!err){ + if (u.length) { + res.jsonp( 400, {message: 'Username already exists!'} ); + } else { user.save( function (er, ok) { if (er) { - res.json( 400, {message: 'Problem registering!'} ); + return res.jsonp( 400, {message: 'Problem registering!'} ); } else { - res.json( 201, ok ); + return res.jsonp( 201, ok ); } } ); } + } ); }, session: function (req, res, next) { @@ -109,7 +108,7 @@ module.exports = function (config, app) { user = req.session.user } console.warn(util.inspect(user, {colors: true})); - res.send({message: 'Your session', data: user}); + return res.send({message: 'Your session', data: user}); } }; @@ -124,3 +123,5 @@ module.exports = function (config, app) { app.post( config.apiBase + '/register', bodyParser.json(), cmsAuth.register ); app.get( config.apiBase + '/session', bodyParser.json(), cmsAuth.session ); }; + +module.exports = cmsAuth; diff --git a/routes/cms-passport.js b/routes/cms-passport.js index c40dd4d..3e69655 100644 --- a/routes/cms-passport.js +++ b/routes/cms-passport.js @@ -1,127 +1,187 @@ -var passport = require( 'passport' ), - BasicStrategy = require( 'passport-http' ).Strategy, - LocalStrategy = require( 'passport-local' ).Strategy, - GoogleStrategy = require( 'passport-google' ).Strategy, - express = require( 'express' ), - path = require( 'path' ), - q = require( 'q' ), - flash = require( 'connect-flash' ), - User = require( './models/user' ), - cookieParser = require( 'cookie-parser' ), - bodyParser = require( 'body-parser' ), - session = require( 'express-session' ); +var passport = require('passport'), + BasicStrategy = require('passport-http').BasicStrategy, + LocalStrategy = require('passport-local').Strategy, + GoogleStrategy = require('passport-google').Strategy, + express = require('express'), + path = require('path'), + q = require('q'), + flash = require('connect-flash'), + User = require('./models/user'), + cookieParser = require('cookie-parser'), + bodyParser = require('body-parser'), + session = require('express-session'), + mongoose = require('mongoose'), + util = require('util'), + User = require('./models/user'), + session = require('express-session'), + crypto = require('crypto'), + bcrypt = require('bcrypt-nodejs'); +/** + * I handle ensuring a user is authenticated. + * @param req + * @param res + * @param next + * @returns {*} + */ var ensureAuthenticated = function (req, res, next) { if (req.isAuthenticated()) { return next(); } - res.redirect( '/login' ); + res.redirect('/login'); }; -module.exports = function (config, app) { + +/** + * I am the cmsPassport module that has various ways of + * authenticating a user. + * @param config - Configuration settings + * @param app - Express app + */ +var cmsPassport = function (config, app) { + +var user = new User(); if (!app) { - throw new Error( 'Must provide express application!' ); + throw new Error('Must provide express application!'); } - passport.serializeUser( function (user, done) { - done( null, user.id ); - } ); - - passport.deserializeUser( function (id, done) { - User.findById( id, function (err, user) { - done( err, user ); - } ); - } ); - - passport.use( new LocalStrategy( { - usernameField: 'email', - passwordField: 'password', - passReqToCallback: true - }, function (username, password, done) { - process.nextTick( function () { - console.warn( 'find by username' ); - User.findByUsername( username ).then( function (user) { - return done( null, user ); - }, function (err) { - return done( null, false ); - } ); - } ); + /* + + */ + var findOrCreate = function(u, done){ + console.log('find', u); + + for (var i = 0; i < u.emails.length; i++) { + var email = u.emails[i].value + User.findOne({ email: email }, function (err, user) { + if (err) { return done(err); } + if (!user) { + console.warn('create user', u); + return done(null, false); + } + return done(null, user); + }); } - ) ); - passport.use( new GoogleStrategy( { - returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' + }; + + /** + * I handle serializing a user. + * @param user + * @param done + */ + var serializeUser = function (user, done) { + done(null, user._id); + }; + + /** + * I handle deserializing a user. + * @param id + * @param done + */ + var deserializeUser = function (id, done) { + User.findById(id, function (err, user) { + done(err, user); + }); + }; + + passport.serializeUser(serializeUser); + + passport.deserializeUser(deserializeUser); + +var strategy = function(username, password, done) { + console.warn('find user', username, password); + User.findOne({ username: username }, function (err, user) { + if (err) { return done(err); } + if (!user) { return done(null, false); } + if (!user.validPassword(password)) { return done(null, false); } + return done(null, user); + }); + }; + + passport.use(new BasicStrategy(strategy)); + passport.use(new LocalStrategy(strategy)); + + passport.use(new GoogleStrategy({ + returnURL: config.host + config.port + '/auth/google/return', + realm: config.host + config.port }, function (identifier, profile, done) { - console.warn( 'googleCallback', profile ); + console.warn('googleCallback', profile); profile.openId = identifier; - User.findOrCreate( profile, function (err, user) { - done( err, user ); - } ); + findOrCreate(profile, function (err, user) { + done(err, user); + }); } - ) ); - - app.use( express.static( path.resolve( __dirname, '../www' ) ) ); - app.set( 'views', path.resolve( __dirname, '../www' ) ); - app.set( 'view engine', 'ejs' ); - app.engine( 'ejs', require( 'ejs-locals' ) ); - app.use( cookieParser() ); - app.use( bodyParser.urlencoded( {extended: false} ) ); - app.use( bodyParser.json() ); - app.use( session( { + )); + + app.use(express.static(path.resolve(config.publicDir))); + app.set('views', path.resolve(config.staticDir)); + app.set('view engine', 'ejs'); + app.engine('ejs', require('ejs-locals')); + app.use(cookieParser()); + app.use(bodyParser.urlencoded({extended: false})); + app.use(bodyParser.json()); + app.use(session({ secret: 'angular-cms', resave: true, saveUninitialized: true - } ) ); - app.use( passport.initialize() ); - app.use( passport.session() ); - app.use( flash() ); - - app.get( '/api/me', passport.authenticate( 'basic', {session: false} ), function (req, res) { - res.json( req.user ); - } ); - - app.all( '*', function (req, res, next) { - console.warn( 'cmsAuth', req.params ); - next(); - } ); + })); + app.use(passport.initialize()); + app.use(passport.session()); + app.use(flash()); - app.get( '/', function (req, res) { - res.render( 'index', {user: req.user, message: 'Please login', status: 'info'} ); - } ); - app.get( '/account', ensureAuthenticated, function (req, res) { - res.render( 'account', {user: req.user} ); - } ); + app.get('/api/me', passport.authenticate('basic', {session: false}), function (req, res) { + res.json(req.user); + }); - app.get( '/login', function (req, res) { - res.render( 'login', {user: req.user, message: 'Please login', status: 'warning'} ); - } ); - - app.post( '/login', - passport.authenticate( 'local', { - successRedirect: '/', + app.all('*', function (req, res, next) { + req.config = JSON.stringify(config); + console.warn('cmsAuth', req.params); + next(); + }); + + app.get('/', function (req, res) { + res.render('index', {user: req.user, message: 'Please login', status: 'info'}); + }); + + app.get('/account', ensureAuthenticated, function (req, res) { + res.render('account', { + user: req.user, + config: req.config + }); + }); + + app.get('/login', function (req, res) { + res.render('login', {user: req.user, message: 'Please login', status: 'warning'}); + }); + + app.post('/login', + passport.authenticate('local', { + successRedirect: '/account', failureRedirect: '/login', failureFlash: false - } ) + }) ); - app.get( '/auth/user', ensureAuthenticated, function (req, res) { - res.json( 200, req.user ); - } ); + app.get('/auth/user', ensureAuthenticated, function (req, res) { + res.json(200, req.user); + }); - app.get( '/auth/logout', function (req, res) { + app.get('/auth/logout', function (req, res) { req.logout(); - res.redirect( options.apiBase ); - } ); + res.redirect(options.apiBase); + }); - app.get( '/auth/google', passport.authenticate( 'google' ) ); - app.get( '/auth/google/return', - passport.authenticate( 'google', { + app.get('/auth/google', passport.authenticate('google')); + app.get('/auth/google/return', + passport.authenticate('google', { successRedirect: '/', failureRedirect: '/login' - } ) ); + })); -}; +}; +module.exports = cmsPassport; diff --git a/routes/cms-rest.js b/routes/cms-rest.js index 0fd127b..c6c286a 100644 --- a/routes/cms-rest.js +++ b/routes/cms-rest.js @@ -1,20 +1,29 @@ -var bodyParser = require( 'body-parser' ), +var express = require('express'), + bodyParser = require( 'body-parser' ), session = require( 'express-session' ), RestResource = require( './rest' ); module.exports = function (config, app) { 'use strict'; + var router = express.Router(); - app.get( config.apiBase + '/plugins', RestResource.plugins ); - app.get( config.apiBase + '/readme', RestResource.readme ); - app.get( config.apiBase, RestResource.index ); +// a middleware with no mount path, gets executed for every request to the router + router.use(function (req, res, next) { + console.log('cms-rest Time:', Date.now()); + next(); + }); + router.get( config.apiBase, RestResource.index ); + router.get( config.apiBase + '/plugins', RestResource.plugins ); + router.get( config.apiBase + '/readme', RestResource.readme ); //Dynamic REST - app.get( config.apiBase + '/:db/:collection/:id?', RestResource.get ) - app.post( config.apiBase + '/:db/:collection/:id?', bodyParser.json(), RestResource.add ) - app.put( config.apiBase + '/:db/:collection/:id?', bodyParser.json(), RestResource.edit ) - app.delete( config.apiBase + '/:db/:collection/:id?', RestResource.destroy ); + router.get( config.apiBase + '/:db/:collection/:id?', RestResource.get ) + router.post( config.apiBase + '/:db/:collection/:id?', bodyParser.json(), RestResource.add ) + router.put( config.apiBase + '/:db/:collection/:id?', bodyParser.json(), RestResource.edit ) + router.delete( config.apiBase + '/:db/:collection/:id?', RestResource.destroy ); console.warn( 'cms-rest', 'initialized' ); + + app.use('/', router); }; diff --git a/routes/cms-routes.js b/routes/cms-routes.js index ed8b6f0..714f8e6 100644 --- a/routes/cms-routes.js +++ b/routes/cms-routes.js @@ -1,9 +1,49 @@ +var mongoose = require('mongoose'), http = require('http'), util = require('util'); + module.exports.mount = function (config, app) { + 'use strict'; + + //Connect to database + mongoose.connect(config.mongodb); + + // CONNECTION EVENTS +// When successfully connected + mongoose.connection.on('connected', function () { + console.log('Mongoose default connection open to ' + config.mongodb); + }); + +// If the connection throws an error + mongoose.connection.on('error',function (err) { + console.log('Mongoose default connection error: ' + err); + }); + +// When the connection is disconnected + mongoose.connection.on('disconnected', function () { + console.log('Mongoose default connection disconnected'); + }); + +// If the Node process ends, close the Mongoose connection + process.on('SIGINT', function() { + mongoose.connection.close(function () { + console.log('Mongoose default connection disconnected through app termination'); + process.exit(0); + }); + }); + + var server = http.createServer(app); + require( './cms-auth' )( config, app ); require( './cms-passport' )( config, app ); require( './cms-rest' )( config, app ); require( './cms-proxy' )( config, app ); - require( './cms-sockets' )( config, app ); - require( './cms-server' )( config, app ); require( './cms-upload' )( config, app ); + require( './cms-sockets' )( config, server ); + require( './cms-server' )( config, app ); + + + + return server.listen(config.port || process.env.PORT, function () { + util.log('App listening on port: ' + config.port + ''.verbose); + util.log(util.inspect(config, {colors: true})); + }); }; diff --git a/routes/cms-server.js b/routes/cms-server.js index d26cb07..d995919 100644 --- a/routes/cms-server.js +++ b/routes/cms-server.js @@ -1,3 +1,31 @@ +var express = require('express'), + path = require('path'), + bodyParser = require( 'body-parser' ); + module.exports = function (config, app) { - console.warn( 'cms-server'); + console.warn( 'cms-server initialized'); + + var router = express.Router(); + + var options = { + dotfiles: 'ignore', + etag: false, + extensions: ['htm', 'html'], + index: false, + maxAge: '1d', + redirect: false, + setHeaders: function (res, path) { + res.set('x-timestamp', Date.now()) + } + }; + + router.use(express.static(config.staticDir, options)); + router.use(express.static(config.publicDir, options)); + router.use('/', function(res, req, next){ + req.send(config.publicDir + path.sep + 'index.html'); + next(); + }); + + app.use('/', router); + }; diff --git a/routes/cms-sockets.js b/routes/cms-sockets.js index 894fc91..bc2c29d 100644 --- a/routes/cms-sockets.js +++ b/routes/cms-sockets.js @@ -1,11 +1,105 @@ + const events = require('events'), util = require('util'); -var cmsSockets = function (config, app) { +var q = require( 'q' ), +WebSocketServer = require('websocket').server, +WebSocketRouter = require('websocket').router; +//////////////////////////// +//## Socket Server +//This is a socket server implementation for 'real' time analytics and other data. +//This is for use with geo analytics and other backend data from the app. listen for connected clients +// +// ### Server Channels +//These are the events that this socket server dispatches. +// +//1. cms:authorization +//2. cms:client:message +//3. cms:client:connect +//4. cms:client:disconnect +//5. cms:server:message +//6. cms:server:disconnect +//7. cms:server:connect +//8. cms: +module.exports = function (config, app) { + 'use strict'; events.EventEmitter.call(this); + console.warn( 'cms-sockts initialized' ); - console.warn( 'cms-sockts' ); + //Start the websocket server + //SocketServer.init(proxyServer); + var cmsSockets = {}, + connections, wsserver, wsclient, router, self = cmsSockets; -}; -util.inherits(cmsSockets, events.EventEmitter); -module.exports = cmsSockets; + var delay = function (fn, time) { + var defer = q.defer(); + setTimeout( function () { + fn(); + defer.resolve(); + }, time ); + return defer.promise; + }; + + var delayedSocketPush = function(socket, time){ + return delay( function (msg) { + socket.emit( 'msg', { + datetime: new Date(), + message: msg, + id: 'Server' + } ); + }, time ); + }; + + //Hold the names of events that this socket server listens for and emits + self.events = { + session: { + pageView: 'cms:session:pageView', + hashChange: 'cms:session:hashChange', + login: 'cms:session:login', + logout: 'cms:session:logout' + }, + server: { + message: 'cms:server:message', + connected: 'cms:server:connect', + disconnected: 'cms:server:disconnect' + }, + client: { + message: 'cms:client:message', + connected: 'cms:client:connect', + disconnected: 'cms:client:disconnect' + } + }; + + + //Store a list of the connected clients + connections = []; + + var serverConfig = { + httpServer: app, + }; + + wsserver = new WebSocketServer(); + wsserver.mount(serverConfig); + + router = new WebSocketRouter(); + router.attachServer(wsserver); + + router.mount('*', 'echo-protocol', function(request) { + console.log('mounted to echo protocol'); + var conn = request.accept(request.origin); + conn.on('message', function(message) { + console.log('routed message', message); + }); + conn.send('hey'); + }); + + router.mount('*', 'update-protocol', function(request) { + console.log('mounted to update protocol'); + var conn = request.accept(request.origin); + conn.on('message', function(message) { + console.log('update all the things', message); + }); }); + + util.inherits(cmsSockets, events.EventEmitter); + +}; diff --git a/routes/cms-upload.js b/routes/cms-upload.js index dcad55c..9e096e3 100644 --- a/routes/cms-upload.js +++ b/routes/cms-upload.js @@ -1,24 +1,14 @@ var easyimage = require( 'easyimage' ); var upload = require( 'jquery-file-upload-middleware' ); var fs = require( 'fs-extra' ); +var path = require('path'); var busboy = require( 'connect-busboy' ); //middleware for form/file upload module.exports = function (config, app) { - app.use( busboy( {immediate: true} ) ); - app.use( function (req, res) { - if (req.busboy) { - req.busboy.on( 'file', function (fieldname, file, filename, encoding, mimetype) { - // ... - console.warn( fieldname, file, filename ); - } ); - req.busboy.on( 'field', function (key, value, keyTruncated, valueTruncated) { - // ... - console.log( key, value ); - } ); - // etc ... - } - } ); + console.log('cms-upload intialized'); + + //### upload //I handled processing a uploaded file on the v2 server. @@ -29,7 +19,7 @@ module.exports = function (config, app) { appid = String( req.param( 'appid' ) ); } - console.log( util.inspect( req, {colors: true} ) ); + console.log( 'upload', util.inspect( req, {colors: true} ) ); //Handle if dynamic filenames are enabled var tmp_filename = req.files.file.name || 'tmp_name'; @@ -107,16 +97,51 @@ module.exports = function (config, app) { }; //Output the results - res.send( json ); + res.json( json ); } ); } ); } ); } ); + + next(); + }; + app.use( busboy( {immediate: true} ) ); + app.use( function (req, res) { + - app.post( config.apiBase + '/upload', upload ); + + if (req.busboy) { + req.busboy.on( 'file', function (fieldname, file, filename, encoding, mimetype) { + var filePath = path.normalize(config.uploadsDestDir + path.sep + filename); + var fstream = fs.createWriteStream(filePath); + file.pipe(fstream); + fstream.on('close', function() { + fs.readFile(filePath, function (err, data) { + if(err){ + throw err; + res.status(400 ).send(err); + } + + res.status(200).json({ + filename: filename, + path: filePath + }); + }); + }); + console.warn('busboy', fieldname, file, filename ); + } ); + req.busboy.on( 'field', function (key, value, keyTruncated, valueTruncated) { + // ... + console.log( 'busboy', key, value ); + } ); + // etc ... + } + } ); + app.post( config.apiBase + '/upload', busboy, upload ); app.get( config.apiBase + '/upload', function (req, res, next) { - res.send( {message: 'Upload a file with a POST.'} ); + res.json( {message: 'Upload a file with a POST.'} ); + next(); } ); }; diff --git a/routes/models/user.js b/routes/models/user.js index f40eb34..1f7e6cb 100644 --- a/routes/models/user.js +++ b/routes/models/user.js @@ -65,7 +65,7 @@ UserSchema.method( 'findOrCreate', function (profile, fn) { UserSchema.method( 'findByUsername', function (username, fn) { console.warn( 'findByUsername', username ); - this.find( {username: username}, function (err, data) { + UserSchema.find( {username: username}, function (err, data) { if (err) { fn( false, err ); } diff --git a/routes/rest.js b/routes/rest.js index a6b68b3..37f788b 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -41,8 +41,8 @@ var MESSAGES = { }; var DS = require('jps-ds').DS; var _ds = new DS({ - //host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', - host: 'localhost/angular-cms', + host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', + //host: 'localhost/angular-cms', models: { 'groups': { title: String, @@ -193,8 +193,6 @@ var RestResource = { }); }, - - //### get //I handle gathering records dynamically from a call to the v2 api. get: function (req, res, next) { diff --git a/server.js b/server.js index 1570592..7aa4c8c 100755 --- a/server.js +++ b/server.js @@ -56,9 +56,6 @@ var cmsRoutes = require('./routes/cms-routes'); cmsRoutes.mount(config, app); -var webapp = http.createServer(app).listen(config.port || process.env.PORT, function () { - util.log(String('App listening on port: ' + config.port).verbose); -}); diff --git a/test/intern.conf.js b/test/intern.conf.js new file mode 100644 index 0000000..a43842b --- /dev/null +++ b/test/intern.conf.js @@ -0,0 +1,79 @@ +// Learn more about configuring this file at . +// These default settings work OK for most people. The options that *must* be changed below are the +// packages, suites, excludeInstrumentation, and (if you want functional tests) functionalSuites. +/* +SAUCE_USERNAME=jonniespratleyge SAUCE_ACCESS_KEY=66f8830c-ec8f-441c-8f06-e8947d830a90 ./node_modules/.bin/intern-runner config=tests/intern +*/ + +define({ + //sauce connect + tunnelOptions: { + username: 'jonniespratleyge', + accessKey: '66f8830c-ec8f-441c-8f06-e8947d830a90' + }, + // The port on which the instrumenting proxy will listen + proxyPort: 9900, + + // A fully qualified URL to the Intern proxy + proxyUrl: 'http://localhost:9900/', + + // Default desired capabilities for all environments. Individual capabilities can be overridden by any of the + // specified browser environments in the `environments` array below as well. See + // https://code.google.com/p/selenium/wiki/DesiredCapabilities for standard Selenium capabilities and + // https://saucelabs.com/docs/additional-config#desired-capabilities for Sauce Labs capabilities. + // Note that the `build` capability will be filled in with the current commit ID from the Travis CI environment + // automatically + capabilities: { + 'selenium-version': '2.41.0' + }, + + // Browsers to run integration testing against. Note that version numbers must be strings if used with Sauce + // OnDemand. Options that will be permutated are browserName, version, platform, and platformVersion; any other + // capabilities options specified for an environment will be copied as-is + environments: [ + {browserName: 'chrome'} + ], + + // Maximum number of simultaneous integration tests that should be executed on the remote WebDriver service + maxConcurrency: 3, + + // Name of the tunnel class to use for WebDriver tests + tunnel: 'SauceLabsTunnel', + + // The desired AMD loader to use when running unit tests (client.html/client.js). Omit to use the default Dojo + // loader + useLoader: { + 'host-node': 'dojo/dojo', + 'host-browser': 'node_modules/dojo/dojo.js' + }, + + // Configuration options for the module loader; any AMD configuration options supported by the specified AMD loader + // can be used here + loader: { + // Packages that should be registered with the loader in each testing environment + packages: [ + { name: 'routes', location: './routes' } + ] + }, + + // Non-functional test suite(s) to run in each browser + suites: [ + 'test/routes/cms-auth-spec', + 'test/routes/cms-passport-spec', + 'test/routes/cms-proxy-spec', + 'test/routes/cms-rest-spec', + 'test/routes/cms-server-spec', + 'test/routes/cms-sockets-spec', + 'test/routes/cms-upload-spec' + /* 'myPackage/tests/foo', + 'myPackage/tests/bar' */ + ], + + // Functional test suite(s) to run in each browser once non-functional tests are completed + functionalSuites: [ + //'tests/functional/index' + /* 'myPackage/tests/functional' */ ], + + // A regular expression matching URLs to files that should not be included in code coverage analysis + excludeInstrumentation: /^(?:tests|node_modules|app\/bower_components|www|config|bin)\// +}); diff --git a/test/protractor/pages/register-page.coffee b/test/protractor/pages/register-page.coffee index 15c3d7e..321dba9 100644 --- a/test/protractor/pages/register-page.coffee +++ b/test/protractor/pages/register-page.coffee @@ -19,7 +19,6 @@ RegisterPage = @password2.sendKeys(password) @agree.click().then(()=> @submit.click() - browser.sleep(1000) ) diff --git a/test/protractor/spec/login-spec.coffee b/test/protractor/spec/login-spec.coffee index 2439953..5db627a 100644 --- a/test/protractor/spec/login-spec.coffee +++ b/test/protractor/spec/login-spec.coffee @@ -9,6 +9,6 @@ describe 'Login:', -> afterEach -> loginPage.logout() it 'should allow a user to login', -> - loginPage.login('test@email.com', 'test').then(()-> + loginPage.login('test@gmail.com', 'test').then(()-> expect(browser.getLocationAbsUrl()).toContain '/dashboard' ) diff --git a/test/routes/cms-auth-spec.js b/test/routes/cms-auth-spec.js new file mode 100644 index 0000000..0befddc --- /dev/null +++ b/test/routes/cms-auth-spec.js @@ -0,0 +1,20 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-auth', + 'should have /auth/login route': function () { + this.skip(); + }, + 'should have /auth/register route': function () { + this.skip(); + }, + 'should have /auth/me route': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/cms-passport-spec.js b/test/routes/cms-passport-spec.js new file mode 100644 index 0000000..88f2972 --- /dev/null +++ b/test/routes/cms-passport-spec.js @@ -0,0 +1,73 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!expect', + 'intern/dojo/node!path', + 'intern/dojo/node!fs', + 'intern/dojo/node!supertest', + 'intern/dojo/node!express', + 'intern/dojo/node!../../routes/cms-passport', +], function (registerSuite, expect, path, fs, request, express, cmsPassport) { + 'use strict'; + + + var app = express(); + var config = JSON.parse(fs.readFileSync(process.cwd() + '/config/config.json')); + config.port = 9191; + + cmsPassport(config, app); + + + registerSuite({ + name: 'cms-passport', + 'should have /proxy route': function () { + this.skip(); + }, + 'should have a /auth/google/callback route': function () { + this.skip(); + }, + 'should have a /auth/google route': function () { + this.skip(); + }, + 'should have /auth/me route': function () { + this.skip(); + }, + 'should have /auth/register route': function () { + this.skip(); + }, + 'POST - /register - should return user on successful registration': function () { + this.skip(); + var dfd = this.async(); + request(app) + .post('/auth/register') + .send({ + "username": Date.now() + "test@email.com", + "email": Date.now() + "test@email.com", + "password": "test", + "metadata": { + "avatar": "", + "name": "Jonnie Dollas" + } + }) + .expect("Content-Type", /json/) + .expect(201, dfd.resolve()); + }, + 'POST - /login - should return user on successful login': function () { + var dfd = this.async(); + var validUser = { + username: 'test@gmail.com', + password: 'test' + }; + request(app) + .post('/auth/login') + .send(validUser) + .expect("Content-Type", /json/) + .expect(200) + .end(function(err, res){ + if (err) {throw err;} + console.log(res.body); + dfd.callback(res); + }); + } + }); +}); diff --git a/test/routes/cms-proxy-spec.js b/test/routes/cms-proxy-spec.js new file mode 100644 index 0000000..426edb6 --- /dev/null +++ b/test/routes/cms-proxy-spec.js @@ -0,0 +1,14 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-proxy', + 'should have /proxy route': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/cms-rest-spec.js b/test/routes/cms-rest-spec.js new file mode 100644 index 0000000..4c5837e --- /dev/null +++ b/test/routes/cms-rest-spec.js @@ -0,0 +1,23 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-rest', + 'GET - /collection - should return array of items': function () { + this.skip(); + }, + 'GET - /collection/:id - should return object item': function () { + this.skip(); + }, + 'POST - /collection - should return object on success': function () { + this.skip(); + }, + 'PUT - /collection/:id - should return object on success': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/cms-server-spec.js b/test/routes/cms-server-spec.js new file mode 100644 index 0000000..8952823 --- /dev/null +++ b/test/routes/cms-server-spec.js @@ -0,0 +1,14 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-server', + 'should have /proxy route': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/cms-sockets-spec.js b/test/routes/cms-sockets-spec.js new file mode 100644 index 0000000..c60b22a --- /dev/null +++ b/test/routes/cms-sockets-spec.js @@ -0,0 +1,14 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-sockets', + 'should have /proxy route': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/cms-upload-spec.js b/test/routes/cms-upload-spec.js new file mode 100644 index 0000000..1e10c2a --- /dev/null +++ b/test/routes/cms-upload-spec.js @@ -0,0 +1,14 @@ +/* global define */ +define([ + 'intern!object', + 'intern/chai!assert', + 'intern/dojo/node!request' +], function (registerSuite, assert, request) { + 'use strict'; + registerSuite({ + name: 'cms-upload', + 'should have /proxy route': function () { + this.skip(); + } + }); +}); diff --git a/test/routes/functional/cms-passport.js b/test/routes/functional/cms-passport.js new file mode 100644 index 0000000..e69de29 diff --git a/test/routes/rest-spec.coffee b/test/routes/rest-spec.coffee deleted file mode 100644 index 616e3b4..0000000 --- a/test/routes/rest-spec.coffee +++ /dev/null @@ -1,32 +0,0 @@ -#Routes Spec -request = require('supertest') -path = require('path') -expect = require('chai').expect - -#//Dynamic rest server -rest = require(path.resolve(__dirname, '../../routes/rest.js')).rest - -console.log(__dirname) -app = new rest({port: 9191}); - -endpoint = 'http://localhost:8181/api/v2' -postData = - "username": "nodetest"+Date.now(), - "email": "nodetest@email.com", - "password": "test", - "active": true, - "groups": ["member"], - "_activation": "", - "_key": "", - "created": new Date(), - "modified": new Date(), - "metadata": {"avatar": "", "name": "Node Test User"} - -describe 'Testing: API Server', () -> - - describe "GET /users", -> - it "respond with json", (done) -> - request(app) - .get '/api/v2/angular-cms/users' - .expect "Content-Type", /json/ - .expect 200, done diff --git a/test/routes/rest-spec.js b/test/routes/rest-spec.js index 5b2eba0..0537429 100644 --- a/test/routes/rest-spec.js +++ b/test/routes/rest-spec.js @@ -1,5 +1,3 @@ - - var request = require('supertest'); var path = require('path'); var fs = require('fs'); @@ -36,14 +34,22 @@ describe('Testing: API Server', function () { it('POST - /api/v2/users/register - should return user on successful registation', function (done) { request(app) .post('/api/v2/register') - .send(postData) + .send({ + "username": Date.now() + "test@email.com", + "email": Date.now() + "test@email.com", + "password": "test", + "metadata": { + "avatar": "", + "name": "Jonnie Dollas" + } + }) .expect("Content-Type", /json/) .expect(201, done); }); it('POST - /api/v2/users/login - should return user on successful login', function (done) { var validUser = { - username: 'test@email.com', + username: 'test@gmail.com', password: 'test' }; request(app) diff --git a/www/_index.html b/www/_index.html new file mode 100644 index 0000000..3e9733e --- /dev/null +++ b/www/_index.html @@ -0,0 +1,53 @@ + + + + + Passport-Local Example + + + + + + + + +
    + +
    +

    Bootstrap starter template

    +

    Use this document as a way to quickly start any new project.
    All you get is this text and a mostly barebones HTML document.

    +
    + +
    + + + + diff --git a/www/account.ejs b/www/account.ejs index d69ad21..b6f1c69 100644 --- a/www/account.ejs +++ b/www/account.ejs @@ -1,3 +1,20 @@ + <% layout('layout') -%> +

    Username: <%= user.username %>

    -

    Email: <%= user.email %>

    \ No newline at end of file +

    Email: <%= user.email %>

    + + + +<%= user %> diff --git a/www/index.html b/www/index.html deleted file mode 100644 index fd8dc8c..0000000 --- a/www/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file diff --git a/www/layout.ejs b/www/layout.ejs index 4fb627b..cffc13a 100644 --- a/www/layout.ejs +++ b/www/layout.ejs @@ -1,4 +1,3 @@ - @@ -9,8 +8,42 @@ -
    - <%- body %> + + +
    + <%- body %> + + +
    + + diff --git a/www/login.ejs b/www/login.ejs index 0e87566..13c98df 100644 --- a/www/login.ejs +++ b/www/login.ejs @@ -2,24 +2,9 @@ <% layout('layout') -%>
    -
    -
    - - -
    -
    - - -
    -
    - -
    -
    -