From 0b06037582ba2ac9a677285362efedc8e28d9364 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Thu, 4 Dec 2014 14:23:55 -0800 Subject: [PATCH 01/39] added page crud --- Gruntfile.js | 8 +- app/scripts/app.coffee | 4 +- app/scripts/controllers/pages.coffee | 20 ++- app/scripts/controllers/users.coffee | 25 ++-- app/styles/main.css | 2 +- app/views/_footer.html | 7 +- app/views/pages.html | 92 +++++++----- app/views/users.html | 209 ++++++++++++++------------ package.json | 216 +++++++++++++-------------- protractor.conf.js | 1 + test/protractor/App.js | 17 +-- 11 files changed, 329 insertions(+), 272 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index ae50c28..82fd306 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -18,7 +18,7 @@ var proxyConfig = { } }; -var LIVERELOAD_PORT = 35729; +var LIVERELOAD_PORT = 35728; var SERVER_PORT = 9000; //var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}); var mountFolder = function (connect, dir) { @@ -72,7 +72,11 @@ module.exports = function (grunt) { options: { livereload: '<%= connect.options.livereload %>' }, - files: ['<%= yeoman.app %>/{,**/}*.html', '.tmp/styles/{,*/}*.css', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'], + files: [ + '<%= yeoman.app %>/{,**/}*.html', + '.tmp/styles/{,*/}*.css', + '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + ], tasks: ['ngtemplates'] } }, diff --git a/app/scripts/app.coffee b/app/scripts/app.coffee index 98086de..6a902b1 100644 --- a/app/scripts/app.coffee +++ b/app/scripts/app.coffee @@ -28,7 +28,7 @@ app = angular.module('angularCmsApp', [ 'mgcrea.ngStrap' #'cms.Templates' ]) - .config ($routeProvider) -> + .config ($routeProvider) -> #Resolve routes routeResolver = # I will cause a 1 second delay @@ -36,7 +36,7 @@ app = angular.module('angularCmsApp', [ delay = $q.defer() $timeout delay.resolve, 1000 delay.promise - + #Router Config $routeProvider .when '/', diff --git a/app/scripts/controllers/pages.coffee b/app/scripts/controllers/pages.coffee index 0695631..7524625 100644 --- a/app/scripts/controllers/pages.coffee +++ b/app/scripts/controllers/pages.coffee @@ -1,9 +1,27 @@ 'use strict' angular.module('angularCmsApp') - .controller 'PagesCtrl', ($scope) -> + .controller 'PagesCtrl', ($scope, DataService) -> $scope.awesomeThings = [ 'HTML5 Boilerplate' 'AngularJS' 'Karma' ] + $scope.page = {} + #Select user + $scope.selectPage = (p) -> + $scope.page = p + + #Get users + $scope.getPages = () -> + DataService.fetch('pages').then((res) -> + $scope.pages = res.data + ) + + #Add user to database + $scope.save = (p) -> + DataService.save('pages', p).then((data) -> + $scope.getPages() + $scope.page = {} + console.log(data) + ) diff --git a/app/scripts/controllers/users.coffee b/app/scripts/controllers/users.coffee index 380f7bb..fe81cbc 100644 --- a/app/scripts/controllers/users.coffee +++ b/app/scripts/controllers/users.coffee @@ -5,28 +5,28 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> 'AngularJS' 'Karma' ] - - $scope.user = + + $scope.user = username: null email: null password: null role: null created: new Date() modified: new Date() - metadata: + metadata: avatar: '' name: null aboue: null - + #Hold the users $scope.users = [] - + #Holds the user groups $scope.groups = ['Admin', 'Member', 'Public'] $scope.getGroups = () -> - DataService.fetch('groups').then((data) -> - $scope.groups = data + DataService.fetch('groups').then((res) -> + $scope.groups = res.data console.log(data) ) @@ -36,8 +36,8 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> #Get users $scope.getUsers = () -> - DataService.fetch('users').then((data) -> - $scope.users = data + DataService.fetch('users').then((res) -> + $scope.users = res.data $scope.getGroups() unless $scope.groups ) @@ -46,7 +46,7 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> ask = confirm "Delete #{user.email}?" if ask - DataService.destroy('users', user).then((data) -> + DataService.destroy('users', user).then((res) -> $scope.users.pop(index) $scope.getUsers() ) @@ -55,9 +55,10 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> $scope.addUser = (user) -> DataService.save('users', user).then((data) -> $scope.getUsers() - #$scope.users.push(user) unless user._id + $scope.users.push(user) unless user._id $scope.user = {} + console.log(data) $('#user-modal').modal('hide') ) - + ) \ No newline at end of file diff --git a/app/styles/main.css b/app/styles/main.css index 50318c5..26c7a87 100755 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -163,7 +163,7 @@ html { } .cms-sidebar.closed .well { - width: 45px; + width: 62px; } diff --git a/app/views/_footer.html b/app/views/_footer.html index e42f934..e7de602 100644 --- a/app/views/_footer.html +++ b/app/views/_footer.html @@ -8,4 +8,9 @@ Version {{App.version}}

- \ No newline at end of file + + +
+ +
{{App.config}}
+
{{App.session}}
diff --git a/app/views/pages.html b/app/views/pages.html index 6e0d103..1101a21 100755 --- a/app/views/pages.html +++ b/app/views/pages.html @@ -1,47 +1,59 @@
-
- -
-
-
- +
+ + +
+
+
+ + + + + + + + - - Permlink: http://jonniespratley.me/?page_id=83 - - -
- h1 - h2 - h3 -
+ + + - - -
-
-
- Publish -
-
-
    +
+ + + + + + + +
#PageBodyStatus
{{page._id}}{{page.title}}{{page.body}}{{page.publish}}{{page.visibility}}
+
+
+
+
+
+ + + Permlink: http://{{App.baseurl}}/?page_id={{page.slug}} + +
+ +
+
+
  • Status: Published
  • Visibility: Public
-
- -
-
-
-
- - + + +
+ + + + diff --git a/app/views/users.html b/app/views/users.html index 3951581..efed6e2 100755 --- a/app/views/users.html +++ b/app/views/users.html @@ -1,9 +1,10 @@

Users -

+ +
@@ -11,37 +12,39 @@

Users
- - - - - - - - + + + + + + + + - - - - - - - + + + + + + - + + +
E-mailUsernameActiveCreatedActions
E-mailActiveCreatedActions
- - {{user.email}} - {{ user.username }} - - {{user.active}} {{user.created | date:'medium'}} +
+ + {{user.email}} + {{ user.username }} + {{group}} + {{user.active}} {{user.created | date:'medium'}}
- -
@@ -63,80 +66,94 @@

- -
- + + +
+ +
+
+ + +
+ + +
+ +
+
+
+ + +
+ +
+
+ + +
+ + +
+
+ -
- -
- -
-
-
- -
- -
-
- - -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -
-
- -
-
-
-
- - - - +
+ +
+ +
+ + +
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ + + + + + + + + + diff --git a/package.json b/package.json index 1de211d..fe2f900 100755 --- a/package.json +++ b/package.json @@ -1,110 +1,110 @@ { - "name": "angular-cms", - "version": "0.0.1", - "description": "This is a lightweight CMS built with Angular.js, Twitter Bootstrap and Node.js.", - "author": "Jonnie Spratley", - "license": "MIT", - "readmeFilename": "README.md", - "homepage": "https://github.com/jonniespratley/angular-cms", - "main": "Gruntfile.js", - "bugs": { - "url": "https://github.com/jonniespratley/angular-cms/issues" - }, - "directories": { - "doc": "docs", - "test": "test" - }, - "repository": { - "type": "git", - "url": "https://github.com/jonniespratley/angular-cms.git" - }, - "keywords": [ - "angular", - "grunt", - "angular-cms", - "yeoman" - ], - "dependencies": { - "body-parser": "^1.9.3", - "body-parser-json": "^1.9.2", - "colors": "~1.0.0", - "easyimage": "~1.0.0", - "emailjs": "~0.3.6", - "express": "~4.0.0", - "http-proxy": "^1.3.0", - "jps-ds": "0.0.1", - "jquery": "~2.1.0", - "jquery-file-upload-middleware": "~0.1.1", - "json-proxy": "^0.3.0", - "logfmt": "~1.2.0", - "markdown": "~0.5.0", - "mongodb": "*", - "mongoose": "*", - "promised-io": "~0.3.4", - "request": "~2.49.0", - "socket.io": "~1.2.1" - }, - "devDependencies": { - "chai": "^1.10.0", - "connect-proxy": "~1.0.2", - "grunt": "~0.4.4", - "grunt-angular-templates": "~0.5.7", - "grunt-autoprefixer": "~2.0.0", - "grunt-bower-install": "~1.6.0", - "grunt-concurrent": "~1.0.0", - "grunt-connect-proxy": "~0.1.10", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-coffee": "~0.12.0", - "grunt-contrib-compass": "~1.0.1", - "grunt-contrib-concat": "~0.5.0", - "grunt-contrib-connect": "~0.9.0", - "grunt-contrib-copy": "~0.7.0", - "grunt-contrib-cssmin": "~0.10.0", - "grunt-contrib-htmlmin": "~0.3.0", - "grunt-contrib-jasmine": "~0.8.1", - "grunt-contrib-jshint": "~0.10.0", - "grunt-contrib-less": "~0.12.0", - "grunt-contrib-uglify": "~0.6.0", - "grunt-contrib-watch": "~0.6.0", - "grunt-google-cdn": "^0.4.3", - "grunt-jasmine-node": "~0.2.1", - "grunt-karma": "^0.9.0", - "grunt-karma-coveralls": "^2.5.1", - "grunt-mocha-test": "^0.12.4", - "grunt-newer": "~0.8.0", - "grunt-ngdocs": "~0.2.6", - "grunt-ngmin": "0.0.3", - "grunt-protractor-runner": "~1.1.4", - "grunt-protractor-webdriver": "~0.2.0", - "grunt-rev": "~0.1.0", - "grunt-svgmin": "~0.2.0", - "grunt-usemin": "~2.0.2", - "jasmine-core": "^2.1.2", - "jasmine-node": "~1.14.5", - "jasmine-reporters": "^1.0.1", - "jshint-stylish": "~1.0.0", - "karma": "^0.12.28", - "karma-chrome-launcher": "^0.1.5", - "karma-coverage": "^0.2.6", - "karma-jasmine": "^0.3.1", - "karma-ng-html2js-preprocessor": "~0.1", - "karma-ng-scenario": "~0.1", - "karma-phantomjs-launcher": "~0.1", - "load-grunt-tasks": "~1.0.0", - "mocha": "~2.0.1", - "protractor": "^1.0.0", - "supertest": "^0.15.0", - "time-grunt": "~1.0.0" - }, - "peerDependencies": { - "grunt": "0.4.x", - "karma": "~0.12.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "grunt test", - "start": "node web.js" - } + "name": "angular-cms", + "version": "0.0.1", + "description": "This is a lightweight CMS built with Angular.js, Twitter Bootstrap and Node.js.", + "author": "Jonnie Spratley", + "license": "MIT", + "readmeFilename": "README.md", + "homepage": "https://github.com/jonniespratley/angular-cms", + "main": "Gruntfile.js", + "bugs": { + "url": "https://github.com/jonniespratley/angular-cms/issues" + }, + "directories": { + "doc": "docs", + "test": "test" + }, + "repository": { + "type": "git", + "url": "https://github.com/jonniespratley/angular-cms.git" + }, + "keywords": [ + "angular", + "grunt", + "angular-cms", + "yeoman" + ], + "dependencies": { + "body-parser": "^1.9.3", + "body-parser-json": "^1.9.2", + "colors": "~0.6.2", + "easyimage": "~0.1.6", + "emailjs": "~0.3.6", + "express": "~3.4.6", + "http-proxy": "^1.3.0", + "jps-ds": "0.0.1", + "jquery": "~2.1.0", + "jquery-file-upload-middleware": "~0.1.1", + "jshint-stylish": "~0.1.5", + "json-proxy": "^0.3.0", + "logfmt": "~0.18.1", + "markdown": "~0.5.0", + "mongodb": "*", + "mongoose": "*", + "promised-io": "~0.3.4", + "request": "~2.34.0", + "socket.io": "~0.9.16" + }, + "devDependencies": { + "chai": "^1.10.0", + "connect-proxy": "~1.0.2", + "grunt": "~0.4.4", + "grunt-angular-templates": "~0.5.1", + "grunt-autoprefixer": "~0.4.0", + "grunt-bower-install": "~0.8.0", + "grunt-concurrent": "~0.4.1", + "grunt-connect-proxy": "~0.1.10", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-coffee": "~0.7.0", + "grunt-contrib-compass": "~0.6.0", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-connect": "~0.5.0", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-cssmin": "~0.7.0", + "grunt-contrib-htmlmin": "~0.1.3", + "grunt-contrib-jasmine": "~0.5.2", + "grunt-contrib-jshint": "~0.7.1", + "grunt-contrib-less": "~0.9.0", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-watch": "~0.5.2", + "grunt-google-cdn": "^0.4.3", + "grunt-jasmine-node": "~0.1.0", + "grunt-karma": "^0.9.0", + "grunt-karma-coveralls": "^2.5.1", + "grunt-mocha-test": "^0.12.4", + "grunt-newer": "~0.5.4", + "grunt-ngdocs": "~0.1.7", + "grunt-ngmin": "0.0.3", + "grunt-protractor-runner": "^1.1.0", + "grunt-protractor-webdriver": "^0.1.8", + "grunt-rev": "~0.1.0", + "grunt-svgmin": "~0.2.0", + "grunt-usemin": "~2.0.2", + "jasmine-core": "^2.1.2", + "jasmine-node": "~1.11.0", + "jasmine-reporters": "^1.0.1", + "karma": "^0.12.28", + "karma-chrome-launcher": "^0.1.5", + "karma-coverage": "^0.2.6", + "karma-jasmine": "^0.3.1", + "karma-ng-html2js-preprocessor": "~0.1", + "karma-ng-scenario": "~0.1", + "karma-phantomjs-launcher": "~0.1", + "load-grunt-tasks": "~0.2.0", + "mocha": "^2.0.1", + "protractor": "^1.0.0", + "supertest": "^0.15.0", + "time-grunt": "~0.2.1" + }, + "peerDependencies": { + "grunt": "0.4.x", + "karma": "~0.12.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "grunt test", + "start": "node web.js" + } } diff --git a/protractor.conf.js b/protractor.conf.js index ee43245..a7ecb9c 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -1,5 +1,6 @@ // An example configuration file. exports.config = { + baseUrl: 'http://localhost:9000', // The address of a running selenium server. seleniumAddress: 'http://localhost:4444/wd/hub', diff --git a/test/protractor/App.js b/test/protractor/App.js index baba5b7..70a6b37 100644 --- a/test/protractor/App.js +++ b/test/protractor/App.js @@ -1,11 +1,10 @@ - /* App.coffee This is the protractor spec that will test the different areas of the application. */ -var UsersPage = function() { +var UsersPage = function () { this.newUserBtn = element(by.buttonText('New User')); this.submitBtn = element(by.buttonText('Submit')); @@ -18,11 +17,11 @@ var UsersPage = function() { summary: element(protractor.By.model('user.meta.summary')) }; - this.get = function() { + this.get = function () { browser.get('http://localhost:9000/#/users'); }; - this.setForm = function(email, username, password, name, summary) { + this.setForm = function (email, username, password, name, summary) { this.newUserBtn.click(); browser.sleep(500); this.inputs.username.sendKeys(username); @@ -37,18 +36,18 @@ var UsersPage = function() { }; -describe('Angular-CMS', function() { +describe('Angular-CMS', function () { var usersPage = null; - describe('Users Page:', function() { - beforeEach(function() { + describe('Users Page:', function () { + beforeEach(function () { usersPage = new UsersPage(); usersPage.get(); }); - it('should be able to create a new user', function() { + it('should be able to create a new user', function () { var username = 'protractor' + Date.now(); - usersPage.setForm(username+'@test.com', username, 'test', 'John Doe', 'This is an example user.'); + usersPage.setForm(username + '@test.com', username, 'test', 'John Doe', 'This is an example user.'); }); }); }); From df504ed6647dda2858ba2bf4d6eade2b59aacbea Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Thu, 4 Dec 2014 14:24:43 -0800 Subject: [PATCH 02/39] added page crud --- test/spec/services/dataservice.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/spec/services/dataservice.coffee b/test/spec/services/dataservice.coffee index eace55b..231038c 100644 --- a/test/spec/services/dataservice.coffee +++ b/test/spec/services/dataservice.coffee @@ -39,7 +39,7 @@ describe 'Service: DataService', () -> it 'should have a destroy method', () -> expect(ds.destroy).toBeDefined() - it 'should invoke create method if _id is not on object', () -> + xit 'should invoke create method if _id is not on object', () -> $httpBackend.expectPOST("#{baseUrl}/posts").respond(200, [{}, {}]) spyOn(ds, '_create') spyOn(ds, '_update') @@ -50,7 +50,7 @@ describe 'Service: DataService', () -> expect(ds._create).toHaveBeenCalled() expect(ds._update).not.toHaveBeenCalled() - it 'should invoke update method if _id is on object', () -> + xit 'should invoke update method if _id is on object', () -> $httpBackend.expectPUT("#{baseUrl}/posts/1").respond(200, {message: 'Success updating object'}) spyOn(ds, '_create') spyOn(ds, '_update') From 1dea27dab0115eaa5be7c6dc77dcabc1023020fc Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Thu, 4 Dec 2014 15:45:47 -0800 Subject: [PATCH 03/39] updated crud operations --- app/scripts/app.coffee | 5 + app/scripts/controllers/pages.coffee | 24 +- app/styles/main.css | 4 +- app/views/_footer.html | 5 - app/views/pages.html | 43 ++-- package.json | 2 +- routes/rest.js | 319 ++++----------------------- 7 files changed, 83 insertions(+), 319 deletions(-) diff --git a/app/scripts/app.coffee b/app/scripts/app.coffee index 6a902b1..72ee9ab 100644 --- a/app/scripts/app.coffee +++ b/app/scripts/app.coffee @@ -81,6 +81,11 @@ app = angular.module('angularCmsApp', [ .when '/pages', templateUrl: 'views/pages.html' controller: 'PagesCtrl' + resolve: + pages : (DataService) -> + DataService.fetch('pages').then((res)-> + return res.data + ) .when '/help', templateUrl: 'views/help.html' controller: 'HelpCtrl' diff --git a/app/scripts/controllers/pages.coffee b/app/scripts/controllers/pages.coffee index 7524625..a73e8d2 100644 --- a/app/scripts/controllers/pages.coffee +++ b/app/scripts/controllers/pages.coffee @@ -1,27 +1,39 @@ 'use strict' angular.module('angularCmsApp') - .controller 'PagesCtrl', ($scope, DataService) -> + .controller 'PagesCtrl', ($scope, $log, pages, DataService) -> $scope.awesomeThings = [ 'HTML5 Boilerplate' 'AngularJS' 'Karma' ] + $scope.pages = pages $scope.page = {} - #Select user + + #Select page $scope.selectPage = (p) -> $scope.page = p + $log.info(p) - #Get users + #Get pages $scope.getPages = () -> DataService.fetch('pages').then((res) -> $scope.pages = res.data ) - #Add user to database + #Save page $scope.save = (p) -> - DataService.save('pages', p).then((data) -> + p.modified = new Date() if p._id? + p.created = new Date() unless p._id? + DataService.save('pages', p).then((res) -> $scope.getPages() $scope.page = {} - console.log(data) + $log.info(res) + ) + + #Delete page + $scope.remove = (p) -> + DataService.destroy('pages', p).then((res)-> + $scope.getPages() + $log.info('Page deleted', res) ) diff --git a/app/styles/main.css b/app/styles/main.css index 26c7a87..6975aca 100755 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -10,7 +10,9 @@ width: 100px; text-align: center; } - +.th-checkbox{ + width: 20px; +} .aside { width: 320px; z-index: 5000; diff --git a/app/views/_footer.html b/app/views/_footer.html index e7de602..0967505 100644 --- a/app/views/_footer.html +++ b/app/views/_footer.html @@ -9,8 +9,3 @@

- -
- -
{{App.config}}
-
{{App.session}}
diff --git a/app/views/pages.html b/app/views/pages.html index 1101a21..59c03b4 100755 --- a/app/views/pages.html +++ b/app/views/pages.html @@ -1,35 +1,32 @@
- - +
- + + + + - - - - - + + + - - - - - - + + + + +
#PageBodyStatusTitleDate
{{page._id}}{{page.title}}{{page.body}}{{page.publish}}{{page.visibility}}
+ {{page.title}} + {{page.publish}} + {{page.created | date:'medium'}}
@@ -42,15 +39,13 @@ Permlink: http://{{App.baseurl}}/?page_id={{page.slug}} -
-
    -
  • Status: Published
  • -
  • Visibility: Public
  • +
      +
    • Status: {{page.status}}
    - +
diff --git a/package.json b/package.json index fe2f900..e3e4ba3 100755 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "emailjs": "~0.3.6", "express": "~3.4.6", "http-proxy": "^1.3.0", - "jps-ds": "0.0.1", + "jps-ds": "~0.0.2", "jquery": "~2.1.0", "jquery-file-upload-middleware": "~0.1.1", "jshint-stylish": "~0.1.5", diff --git a/routes/rest.js b/routes/rest.js index ca2d61d..d3a3da1 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -41,12 +41,18 @@ var MESSAGES = { USER_REGISTRATION_EXISTS: 'User already in exists.' }; - - var DS = require('jps-ds').DS; - var _ds = new DS({ - host: 'localhost/angular-cms' + host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', + models: { + 'users': { username: String, email: String, password: String, active: Boolean, meta: Object, token: String, created: Date, updated: Date }, + 'uploads': { title: String, body: String, image: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String}, + 'posts': { title: String, body: String, image: String, published: Boolean, created: Date, updated: Date, status: String, userid: String, meta: Object}, + 'pages': { title: String, body: String, image: String, published: Boolean, created: Date, updated: Date, status: String, userid: String, meta: Object}, + 'themes': { }, + 'widgets': { title: String, body: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String, active: Boolean}, + 'plugins': { title: String, body: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String, active: Boolean} + } }); function delay(ms, value) { @@ -121,6 +127,7 @@ var RestResource = { message: 'REST API Server ' + RestResource.useversion }); }, + //### v1index //I handle displaying a message with the version for v1 index. v1index: function (req, res, next) { @@ -130,117 +137,7 @@ var RestResource = { res.json(JSON.parse(body)); }); }, - //### v1get - //I handle forwarding requests to the www.myappmatrix.com v1 api server and handling the results. - v1get: function (req, res, next) { - var url = RestResource.urls[RestResource.useversion] + '/Api/getall/' + req.param('model') + '?appid=' + req.param('appid'); - - console.log('URL', url.debug); - - var options = { - url: url, - qs: { - appid: req.param('appid') - }, - headers: { - Authorization: 'Basic: bXk6ZnJlZA==' - } - }; - - if (req.param('appid')) { - options.qs['appid'] = String(req.param('appid')); - } - request(options, function (error, response, body) { - if (!error) { - try { - res.json(JSON.parse(body).results); - } catch (e) { - console.log(e); - res.json(Array({ - status: false, - message: 'There was an error parsing the data.' - })); - } - } - }); - }, - //### v1method - //I handle forwarding method requests to a v1 api server and handling the results. - v1method: function (req, res, next) { - var url = RestResource.urls[RestResource.useversion] + '/' + req.param('method'); - - var options = { - url: url, - method: 'GET', - headers: { - Authorization: 'Basic: bXk6ZnJlZA==' - } - }; - - options.qs = {} - - if (req.param('appid')) { - options.qs['appid'] = String(req.param('appid')); - } - request(options, function (error, response, body) { - if (!error) { - try { - res.json(JSON.parse(body).results); - } catch (e) { - console.log(e); - res.json(Array({ - status: false, - message: 'There was an error parsing the data.' - })); - } - } - }); - }, - //### v1add - //I handle forwarding post requests to a v1 api server. - v1add: function (req, res, next) { - RestResource.version = 'v1'; - - var url = RestResource.urls[RestResource.useversion] + '/' + req.param('collection'); - var method = 'POST'; - if (req.param('id')) { - method = 'PUT'; - url += '/' + req.param('id'); - } - - var options = { - url: url, - method: method, - json: req.body, - headers: { - Authorization: 'Basic: bXk6ZnJlZA==' - } - }; - - options.qs = {} - - if (req.param('appid')) { - options.qs['appid'] = String(req.param('appid')); - } - - console.log(url); - - request(options, function (error, response, body) { - if (!error) { - try { - - res.json(body); - } catch (e) { - console.log(e); - res.json(Array({ - status: false, - message: 'There was an error parsing the data.' - })); - } - } - }); - }, //### v2index //I handle displaying a message for the v2 api index. v2index: function (req, res, next) { @@ -374,7 +271,7 @@ var RestResource = { insert: function (collection, data) { console.log(data); var deferred = new Deferred(); - //Open db + var db = new mongo.Db(config.db.name, new mongo.Server(config.db.host, config.db.port, {safe: false})); db.open(function (err, db) { db.collection('users', function (err, collection) { @@ -589,155 +486,33 @@ var RestResource = { //### get //I handle gathering records dynamically from a call to the v2 api. get: function (req, res, next) { - var query = req.query.query ? JSON.parse(req.query.query) : {}; - var self = this; - // Providing an id overwrites giving a query in the URL - if (req.params.id) { - query = { - '_id': new BSON.ObjectID(req.params.id) - }; - } - //Pass a appid param to get all records for that appid - if (req.param('appid')) { - query['appid'] = String(req.param('appid')); - } - var options = req.params.options || {}; - //Test array of legal query params - var test = ['limit', 'sort', 'fields', 'skip', 'hint', 'explain', 'snapshot', 'timeout']; - //loop and test - for (o in req.query) { - if (test.indexOf(o) >= 0) { - options[o] = req.query[o]; - } - } - //Log for interal usage - console.log('query', query, 'options', options); - //new database instance - var db = new mongo.Db(req.params.db, new mongo.Server(config.db.host, config.db.port, { - auto_reconnect: true, - safe: true - })); - //open database - db.open(function (err, db) { - if (err) { - console.log(err); - } else { - //prep collection - db.collection(req.params.collection, function (err, collection) { - //query - collection.find(query, options, function (err, cursor) { - cursor.toArray(function (err, docs) { - console.log(docs); - if (err) { - console.log(err); - } else { - var result = []; - if (req.params.id) { - if (docs.length > 0) { - result = docs[0]; - res.header('Content-Type', 'application/json'); - res.jsonp(200, result); - } else { - res.jsonp(404, 'Not found'); - //res.send(404); - } - } else { - docs.forEach(function (doc) { - result.push(doc); - }); - res.header('Content-Type', 'application/json'); - res.jsonp(200, result); - } - db.close(); - } - }); - }); - }); - } + console.warn('find all', req.params.collection); + _ds.findAll(req.params.collection).then(function(data){ + res.send(data); + }, function(err){ + res.send(err); }); }, //### add //I handle adding a record to the database. add: function (req, res, next) { - var data = req.body; - var results = []; - var response = {}; - - if (data) { - var db = new mongo.Db(req.params.db, new mongo.Server(config.db.host, config.db.port, { - auto_reconnect: true, - safe: true - })); - db.open(function (err, db) { - if (err) { - console.log(err); - } else { - db.collection(req.params.collection, function (err, collection) { - collection.count(function (err, count) { - console.log("There are " + count + " records."); - }); - }); - - db.collection(req.params.collection, function (err, collection) { - //Check if the posted data is an array, if it is, then loop and insert each document - if (data.length) { - //insert all docs - for (var i = 0; i < data.length; i++) { - var obj = data[i]; - console.log(obj); - collection.insert(obj, function (err, docs) { - results.push(obj); - }); - } - response.results = results; - db.close(); - res.header('Content-Type', 'application/json'); - res.jsonp(200, response); - } else { - collection.insert(req.body, function (err, docs) { - db.close(); - if (!err) { - response.status = 'ok'; - response.data = docs[0]; - //res.header('Location', '/' + req.params.db + '/' + req.params.collection + '/' + docs[0]._id.toHexString()); - res.header('Content-Type', 'application/json'); - res.send(response, 201); - - } - }); - } - }); - } - }); - } else { - res.header('Content-Type', 'application/json'); - res.send('{"ok":0}', 200); - } + _ds.create(req.params.collection, req.body).then(function(data){ + console.warn( 'create', data); + res.send(data); + }, function(err){ + res.send(err); + }); }, //### edit //I handle edit: function (req, res, next) { - var spec = { - '_id': new BSON.ObjectID(req.params.id) - }; - var db = new mongo.Db(req.params.db, new mongo.Server(config.db.host, config.db.port, { - 'auto_reconnect': true, - 'safe': true - })); - - console.log('Upating: ' + JSON.stringify(req.body).warn); - - - db.open(function (err, db) { - db.collection(req.params.collection, function (err, collection) { - collection.update(spec, req.body, true, function (err, docs) { - res.header('Location', '/' + req.params.db + '/' + req.params.collection + '/' + req.params.id); - res.header('Content-Type', 'application/json'); - res.send('{"ok":1}'); - db.close(); - console.log('Location', '/' + req.params.db + '/' + req.params.collection + '/' + req.params.id); - }); - }); + var data = req.body; + delete data._id; + _ds.update(req.params.collection, req.params.id, data).then(function(data){ + console.warn(data); + res.send(data); + }, function(err){ + res.send(err); }); }, //### view @@ -747,27 +522,11 @@ var RestResource = { //### destroy //I handle destroy: function (req, res, next) { - var params = { - _id: new BSON.ObjectID(req.params.id) - }; - console.log('Delete by id ' + req.params); - var db = new mongo.Db(req.params.db, new mongo.Server(config.db.host, config.db.port, { - auto_reconnect: true, - safe: true - })); - db.open(function (err, db) { - db.collection(req.params.collection, function (err, collection) { - console.log('found ', collection.collectionName, params); - collection.remove(params, function (err, docs) { - if (!err) { - res.header('Content-Type', 'application/json'); - res.send('{"ok":1}'); - db.close(); - } else { - console.log(err); - } - }); - }); + _ds.destroy(req.params.collection, req.params.id).then(function(data){ + console.warn(data); + res.send(data); + }, function(err){ + res.send(err); }); }, //### cloudupload @@ -824,9 +583,8 @@ var RestResource = { //### v2 API //v2 mongo rest api app.get('/api/v2', RestResource.v2index); -app.post('/api/v1/imagecrop', RestResource.imageCrop); +app.post('/api/v2/imagecrop', RestResource.imageCrop); app.post('/api/v2/cloudupload', RestResource.cloudupload); - app.post('/api/v2/upload', RestResource.upload); //Always users table @@ -834,7 +592,7 @@ app.post('/api/v2/users/login', bodyParser.json(), RestResource.login); app.post('/api/v2/users/register', bodyParser.json(), RestResource.register); app.post('/api/v2/users/session', bodyParser.json(), RestResource.session); - +//Dynamic REST app.get('/api/v2/:db/:collection/:id?', RestResource.get); app.post('/api/v2/:db/:collection', bodyParser.json(), RestResource.add); app.put('/api/v2/:db/:collection/:id', bodyParser.json(), RestResource.edit); @@ -842,11 +600,9 @@ app.delete('/api/v2/:db/:collection/:id', RestResource.destroy); //Readme - var markdown = require("markdown").markdown; app.get('/api/v2/README', function (res, req) { var localPath = __dirname + '/../README.md'; - fs.readFile(localPath, 'utf8', function (err, data) { if (err) { req.end('There was an error.'); @@ -859,7 +615,6 @@ app.get('/api/v2/README', function (res, req) { req.end(data); } console.log(data); - }); }); /* ======================[ @TODO: Other Rest Utility Methods ]====================== */ From 174637e97904f42ff1ff09fce5356ccf835cc5e7 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Thu, 4 Dec 2014 15:54:12 -0800 Subject: [PATCH 04/39] fixed spec --- test/spec/controllers/pages.coffee | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/test/spec/controllers/pages.coffee b/test/spec/controllers/pages.coffee index 7639a2d..021985f 100644 --- a/test/spec/controllers/pages.coffee +++ b/test/spec/controllers/pages.coffee @@ -2,18 +2,21 @@ describe 'Controller: PagesCtrl', () -> - # load the controller's module - beforeEach module 'angularCmsApp' + # load the controller's module + beforeEach module 'angularCmsApp' - PagesCtrl = {} - scope = {} + PagesCtrl = {} + scope = {} - # Initialize the controller and a mock scope - beforeEach inject ($controller, $rootScope) -> - scope = $rootScope.$new() - PagesCtrl = $controller 'PagesCtrl', { - $scope: scope - } + # Initialize the controller and a mock scope + beforeEach inject ($controller, $rootScope, $injector) -> + scope = $rootScope.$new() + PagesCtrl = $controller 'PagesCtrl', { + $scope: scope + $log: $injector.get('$log') + pages: [] + DataService: $injector.get('DataService') + } - it 'should attach a list of awesomeThings to the scope', () -> - expect(scope.awesomeThings.length).toBe 3 + it 'should attach a list of awesomeThings to the scope', () -> + expect(scope.awesomeThings.length).toBe 3 From b86b0ff18bdb24075ff1a1fa159bcbc9e98a5f10 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 00:56:26 +0000 Subject: [PATCH 05/39] updated git ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e979917..9791eff 100755 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ coverage/ atlassian-ide-plugin.xml docs dist +.c9 \ No newline at end of file From 68bf1be4e37ee7c8aea257a9227278dffd28e28c Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 14:24:35 -0800 Subject: [PATCH 06/39] updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 58a3d01..7cd73ec 100755 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ This is a boilerplate CMS built with Angular, Twitter Bootstrap and Node; it is [![Coverage Status](https://coveralls.io/repos/jonniespratley/angular-cms/badge.png)](https://coveralls.io/r/jonniespratley/angular-cms)[![Dependency Status](https://david-dm.org/jonniespratley/angular-cms.svg)](https://david-dm.org/jonniespratley/angular-cms) +[![Dependency Status](https://david-dm.org/jonniespratley/angular-cms.svg)](https://david-dm.org/jonniespratley/angular-cms) + ### Technologies Some featured technologies used in this project include the following: From e91eb0463a1b01e090ac92cdfce4b93e8489580b Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 15:21:36 -0800 Subject: [PATCH 07/39] added passport --- app/scripts/controllers/users.coffee | 6 +- config/config.json | 2 + package.json | 219 +++++----- routes/cms-auth.js | 1 + routes/rest.js | 578 +++++++++------------------ server.js | 78 +--- 6 files changed, 311 insertions(+), 573 deletions(-) create mode 100644 routes/cms-auth.js diff --git a/app/scripts/controllers/users.coffee b/app/scripts/controllers/users.coffee index fe81cbc..f1903ec 100644 --- a/app/scripts/controllers/users.coffee +++ b/app/scripts/controllers/users.coffee @@ -10,13 +10,13 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> username: null email: null password: null - role: null + role: 'member' created: new Date() modified: new Date() metadata: avatar: '' name: null - aboue: null + about: null #Hold the users $scope.users = [] @@ -61,4 +61,4 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> $('#user-modal').modal('hide') ) -) \ No newline at end of file +) diff --git a/config/config.json b/config/config.json index 0dd4674..ae12d79 100644 --- a/config/config.json +++ b/config/config.json @@ -1,5 +1,7 @@ { + "host": "http://localhost", "port": 8181, + "apiBase": "/api/v2", "version": "v2", "security": {"salt": ""}, "db": { diff --git a/package.json b/package.json index e3e4ba3..853cc0f 100755 --- a/package.json +++ b/package.json @@ -1,110 +1,113 @@ { - "name": "angular-cms", - "version": "0.0.1", - "description": "This is a lightweight CMS built with Angular.js, Twitter Bootstrap and Node.js.", - "author": "Jonnie Spratley", - "license": "MIT", - "readmeFilename": "README.md", - "homepage": "https://github.com/jonniespratley/angular-cms", - "main": "Gruntfile.js", - "bugs": { - "url": "https://github.com/jonniespratley/angular-cms/issues" - }, - "directories": { - "doc": "docs", - "test": "test" - }, - "repository": { - "type": "git", - "url": "https://github.com/jonniespratley/angular-cms.git" - }, - "keywords": [ - "angular", - "grunt", - "angular-cms", - "yeoman" - ], - "dependencies": { - "body-parser": "^1.9.3", - "body-parser-json": "^1.9.2", - "colors": "~0.6.2", - "easyimage": "~0.1.6", - "emailjs": "~0.3.6", - "express": "~3.4.6", - "http-proxy": "^1.3.0", - "jps-ds": "~0.0.2", - "jquery": "~2.1.0", - "jquery-file-upload-middleware": "~0.1.1", - "jshint-stylish": "~0.1.5", - "json-proxy": "^0.3.0", - "logfmt": "~0.18.1", - "markdown": "~0.5.0", - "mongodb": "*", - "mongoose": "*", - "promised-io": "~0.3.4", - "request": "~2.34.0", - "socket.io": "~0.9.16" - }, - "devDependencies": { - "chai": "^1.10.0", - "connect-proxy": "~1.0.2", - "grunt": "~0.4.4", - "grunt-angular-templates": "~0.5.1", - "grunt-autoprefixer": "~0.4.0", - "grunt-bower-install": "~0.8.0", - "grunt-concurrent": "~0.4.1", - "grunt-connect-proxy": "~0.1.10", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-coffee": "~0.7.0", - "grunt-contrib-compass": "~0.6.0", - "grunt-contrib-concat": "~0.3.0", - "grunt-contrib-connect": "~0.5.0", - "grunt-contrib-copy": "~0.4.1", - "grunt-contrib-cssmin": "~0.7.0", - "grunt-contrib-htmlmin": "~0.1.3", - "grunt-contrib-jasmine": "~0.5.2", - "grunt-contrib-jshint": "~0.7.1", - "grunt-contrib-less": "~0.9.0", - "grunt-contrib-uglify": "~0.2.0", - "grunt-contrib-watch": "~0.5.2", - "grunt-google-cdn": "^0.4.3", - "grunt-jasmine-node": "~0.1.0", - "grunt-karma": "^0.9.0", - "grunt-karma-coveralls": "^2.5.1", - "grunt-mocha-test": "^0.12.4", - "grunt-newer": "~0.5.4", - "grunt-ngdocs": "~0.1.7", - "grunt-ngmin": "0.0.3", - "grunt-protractor-runner": "^1.1.0", - "grunt-protractor-webdriver": "^0.1.8", - "grunt-rev": "~0.1.0", - "grunt-svgmin": "~0.2.0", - "grunt-usemin": "~2.0.2", - "jasmine-core": "^2.1.2", - "jasmine-node": "~1.11.0", - "jasmine-reporters": "^1.0.1", - "karma": "^0.12.28", - "karma-chrome-launcher": "^0.1.5", - "karma-coverage": "^0.2.6", - "karma-jasmine": "^0.3.1", - "karma-ng-html2js-preprocessor": "~0.1", - "karma-ng-scenario": "~0.1", - "karma-phantomjs-launcher": "~0.1", - "load-grunt-tasks": "~0.2.0", - "mocha": "^2.0.1", - "protractor": "^1.0.0", - "supertest": "^0.15.0", - "time-grunt": "~0.2.1" - }, - "peerDependencies": { - "grunt": "0.4.x", - "karma": "~0.12.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "grunt test", - "start": "node web.js" - } + "name": "angular-cms", + "version": "0.0.1", + "description": "This is a lightweight CMS built with Angular.js, Twitter Bootstrap and Node.js.", + "author": "Jonnie Spratley", + "license": "MIT", + "readmeFilename": "README.md", + "homepage": "https://github.com/jonniespratley/angular-cms", + "main": "Gruntfile.js", + "bugs": { + "url": "https://github.com/jonniespratley/angular-cms/issues" + }, + "directories": { + "doc": "docs", + "test": "test" + }, + "repository": { + "type": "git", + "url": "https://github.com/jonniespratley/angular-cms.git" + }, + "keywords": [ + "angular", + "grunt", + "angular-cms", + "yeoman" + ], + "dependencies": { + "body-parser": "^1.9.3", + "body-parser-json": "^1.9.2", + "colors": "~0.6.2", + "easyimage": "~0.1.6", + "emailjs": "~0.3.6", + "express": "~3.4.6", + "http-proxy": "^1.3.0", + "jps-ds": "~0.0.2", + "jquery": "~2.1.0", + "jquery-file-upload-middleware": "~0.1.1", + "jshint-stylish": "~0.1.5", + "json-proxy": "^0.3.0", + "logfmt": "~0.18.1", + "markdown": "~0.5.0", + "mongodb": "*", + "mongoose": "*", + "npmlog": "^0.1.1", + "passport": "^0.2.1", + "passport-google": "^0.3.0", + "promised-io": "~0.3.4", + "request": "~2.34.0", + "socket.io": "~0.9.16" + }, + "devDependencies": { + "chai": "^1.10.0", + "connect-proxy": "~1.0.2", + "grunt": "~0.4.4", + "grunt-angular-templates": "~0.5.1", + "grunt-autoprefixer": "~0.4.0", + "grunt-bower-install": "~0.8.0", + "grunt-concurrent": "~0.4.1", + "grunt-connect-proxy": "~0.1.10", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-coffee": "~0.7.0", + "grunt-contrib-compass": "~0.6.0", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-connect": "~0.5.0", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-cssmin": "~0.7.0", + "grunt-contrib-htmlmin": "~0.1.3", + "grunt-contrib-jasmine": "~0.5.2", + "grunt-contrib-jshint": "~0.7.1", + "grunt-contrib-less": "~0.9.0", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-watch": "~0.5.2", + "grunt-google-cdn": "^0.4.3", + "grunt-jasmine-node": "~0.1.0", + "grunt-karma": "^0.9.0", + "grunt-karma-coveralls": "^2.5.1", + "grunt-mocha-test": "^0.12.4", + "grunt-newer": "~0.5.4", + "grunt-ngdocs": "~0.1.7", + "grunt-ngmin": "0.0.3", + "grunt-protractor-runner": "^1.1.0", + "grunt-protractor-webdriver": "^0.1.8", + "grunt-rev": "~0.1.0", + "grunt-svgmin": "~0.2.0", + "grunt-usemin": "~2.0.2", + "jasmine-core": "^2.1.2", + "jasmine-node": "~1.11.0", + "jasmine-reporters": "^1.0.1", + "karma": "^0.12.28", + "karma-chrome-launcher": "^0.1.5", + "karma-coverage": "^0.2.6", + "karma-jasmine": "^0.3.1", + "karma-ng-html2js-preprocessor": "~0.1", + "karma-ng-scenario": "~0.1", + "karma-phantomjs-launcher": "~0.1", + "load-grunt-tasks": "~0.2.0", + "mocha": "^2.0.1", + "protractor": "^1.0.0", + "supertest": "^0.15.0", + "time-grunt": "~0.2.1" + }, + "peerDependencies": { + "grunt": "0.4.x", + "karma": "~0.12.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "grunt test", + "start": "node web.js" + } } diff --git a/routes/cms-auth.js b/routes/cms-auth.js new file mode 100644 index 0000000..b7944a5 --- /dev/null +++ b/routes/cms-auth.js @@ -0,0 +1 @@ +var passport = require('passport'), GoogleStrategy = require('passport-google').Strategy, log = require('npmlog'); var cmsAuth = function (options, app) { if (!app) { throw new Error('Must provide express application!'); } console.warn('cmsAuth', options); var baseUrl = options.host + ':' + options.port; var authed = function(req, res, next) { if (req.isAuthenticated()) { return next(); } else { res.json(503, { error: "service_unavailable", reason: "authentication_unavailable" }); } }; //Setup app.use(passport.initialize()); app.use(passport.session()); app.all('*', function(req, res, next){ console.warn('cmsAuth', req.params); next(); }); app.get('/api/user', authed, function(req, res){ res.json(req.user); }); app.get('/auth/google/:return?', passport.authenticate('google', { successRedirect: baseUrl }) ); app.get('/auth/logout', function(req, res){ req.logout(); res.redirect(options.apiBase); }); passport.use(new GoogleStrategy({ returnURL: baseUrl + '/auth/google/return', realm: baseUrl }, function (identifier, profile, done) { profile.identifier = identifier; return done(null, profile); })); passport.serializeUser(function (user, done) { done(null, user.identifier); }); passport.deserializeUser(function (id, done) { done(null, {identifier: id}); }); return app; }; module.exports = cmsAuth; \ No newline at end of file diff --git a/routes/rest.js b/routes/rest.js index d3a3da1..6045035 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -16,23 +16,19 @@ */ //## Required Modules -var mongo = require('mongodb'); -var mongoose = require('mongoose'); var crypto = require('crypto'); -var Server = mongo.Server; var path = require('path'); -var Db = mongo.Db; -var BSON = mongo.BSONPure; var express = require('express'); -var fs = require('fs'); -var app = express(); +var fs = require('fs'), util = require('util'); var request = require('request'); +var easyimage = require('easyimage'); var upload = require('jquery-file-upload-middleware'); -var easyimg = require('easyimage'); var sio = require('socket.io'); var Deferred = require("promised-io/promise").Deferred; var when = require("promised-io/promise"); var bodyParser = require('body-parser'); +var markdown = require("markdown").markdown; + //Strings for results var MESSAGES = { @@ -45,13 +41,79 @@ var DS = require('jps-ds').DS; var _ds = new DS({ host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', models: { - 'users': { username: String, email: String, password: String, active: Boolean, meta: Object, token: String, created: Date, updated: Date }, - 'uploads': { title: String, body: String, image: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String}, - 'posts': { title: String, body: String, image: String, published: Boolean, created: Date, updated: Date, status: String, userid: String, meta: Object}, - 'pages': { title: String, body: String, image: String, published: Boolean, created: Date, updated: Date, status: String, userid: String, meta: Object}, - 'themes': { }, - 'widgets': { title: String, body: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String, active: Boolean}, - 'plugins': { title: String, body: String, path: String, filename: String, meta: Object, created: Date, updated:Date, userid: String, active: Boolean} + 'groups': { + title: String, + body: String, + slug: String, + created: Date, + updated: Date + }, + 'users': { + username: String, + email: String, + password: String, + active: Boolean, + meta: Object, + token: String, + created: Date, + updated: Date + }, + 'uploads': { + title: String, + body: String, + image: String, + path: String, + filename: String, + meta: Object, + created: Date, + updated: Date, + userid: String + }, + 'posts': { + title: String, + body: String, + image: String, + published: Boolean, + created: Date, + updated: Date, + status: String, + userid: String, + meta: Object + }, + 'pages': { + title: String, + body: String, + image: String, + published: Boolean, + created: Date, + updated: Date, + status: String, + userid: String, + meta: Object + }, + 'themes': {}, + 'widgets': { + title: String, + body: String, + path: String, + filename: String, + meta: Object, + created: Date, + updated: Date, + userid: String, + active: Boolean + }, + 'plugins': { + title: String, + body: String, + path: String, + filename: String, + meta: Object, + created: Date, + updated: Date, + userid: String, + active: Boolean + } } }); @@ -78,15 +140,6 @@ var hashPassword = function (pass, salt) { //## Configuration -//### Cloud Files Config -var cloudfilesConfig = { - auth: { - username: '', - apiKey: '', - host: 'lon.auth.api.rackspacecloud.com' - }, - servicenet: true -}; //### Colors Config var colors = require('colors'); @@ -114,12 +167,15 @@ var RestResource = { this.config = config; return this; }, - useversion: 'v2', urls: { v1: 'https://www..com', v2: '/api/v2/' }, + log: function(){ + console.log(util.inspect(arguments, {colors: true})); + + }, //### index //I handle displaying a message with the version for this api. index: function (req, res, next) { @@ -127,44 +183,6 @@ var RestResource = { message: 'REST API Server ' + RestResource.useversion }); }, - - //### v1index - //I handle displaying a message with the version for v1 index. - v1index: function (req, res, next) { - RestResource.useversion = 'v1'; - request(RestResource.urls[RestResource.useversion], function (error, response, body) { - console.log(error, response, body); - res.json(JSON.parse(body)); - }); - }, - - //### v2index - //I handle displaying a message for the v2 api index. - v2index: function (req, res, next) { - RestResource.version = 'v2'; - res.json({ - message: 'REST API Server ' + RestResource.useversion - }); - }, - - findOne: function (req, table, query, success, fail) { - //Open db - var db = new mongo.Db('angular-cms', new mongo.Server(config.db.host, config.db.port)); - db.open(function (err, db) { - db.collection(table, function (err, collection) { - var options = req.params.options || {}; - collection.findOne(query, options, function (err, cursor) { - if (cursor != null) { - success(cursor); - } else { - err = "No data found!"; - fail(err); - } - db.close(); - }); - }); - }); - }, /** * //### login //I handle trying to authorized a user with the v1 api server. @@ -189,25 +207,10 @@ var RestResource = { console.log('Login Query: ', query); - var deferred = new Deferred(); - - var userFound = false; - RestResource.findOne(req, 'users', query, function (u) { - userFound = true; - res.jsonp(200, { - success: true, - result: u - }); - - }, function (error) { - userFound = false; - res.jsonp(404, { - status: false, - error: true, - message: 'Invalid email/password.' - }); - - + _ds.findOne(req.params.collection, req.params.id).then(function (data) { + res.send(data); + }, function (err) { + res.send(err); }); @@ -224,70 +227,12 @@ var RestResource = { query = { email: req.body.email }; - - data.password = hashPassword(req.body.password, req.body.email), - console.log(String("Register user").debug, req.body); - - - RestResource.findOne(req, 'users', query, function (u) { - user = u; - res.jsonp(404, { - status: false, - message: MESSAGES.USER_REGISTRATION_EXISTS - }); - - }, function (error) { - user = null; - var db = new mongo.Db(config.db.name, new mongo.Server(config.db.host, config.db.port, {safe: true})); - db.open(function (err, db) { - db.collection('users', function (err, collection) { - collection.insert(data, function (err, docs) { - console.log(err, docs); - if (!err) { - res.header('Content-Type', 'application/json'); - res.jsonp(200, { - status: true, - message: MESSAGES.USER_REGISTRATION_SUCCESS, - user: req.body - }); - } else { - res.jsonp(404, { - status: false, - message: MESSAGES.USER_REGISTRATION_ERROR - }); - console.log(error.warn); - } - db.close(); - }); - }); - }); - - }); + console.log(String("Register user").debug, req.body); }, session: function (req, res, next) { }, - insert: function (collection, data) { - console.log(data); - var deferred = new Deferred(); - - var db = new mongo.Db(config.db.name, new mongo.Server(config.db.host, config.db.port, {safe: false})); - db.open(function (err, db) { - db.collection('users', function (err, collection) { - collection.insert(data, function (err, docs) { - console.log(err, docs); - if (!err) { - deferred.resolve(true); - } else { - deferred.reject(false); - } - db.close(); - }); - }); - }); - return deferred.promise; - }, //### upload //I handled processing a uploaded file on the v2 server. upload: function (req, res, next) { @@ -337,10 +282,6 @@ var RestResource = { if (err) { console.error('File Rename Error:', err); } - ; - - //Upload the original to cloudfiles - //rackspaceUpload(target_path, target_dir, filename); //Create the thumb directory fs.mkdir(thumb_dir, 0777, function (e) { @@ -361,11 +302,6 @@ var RestResource = { console.log('easyimg', imgOptions, e); - //Upload thumb to rackspace - /* - rackspaceUpload(thumb_path, thumb_dir, filename, function(results) { - }); - */ //set the new path on the file req.files.file.target_dir = target_dir; @@ -394,112 +330,32 @@ var RestResource = { }); }); }, - //### imageCrop - //I handle processing a uploaded image, cropping it and moving it to the proper directory, and uploaded to Rackspace Cloud Files. - imageCrop: function (req, res, next) { - var appid = null; - - if (req.param('appid')) { - appid = String(req.param('appid')); - } - - //Handle if dynamic filenames are enabled - var tmp_filename = req.files.file.name; - var filename = tmp_filename; - var tmp_path = req.files.file.path; - var target_dir = config.uploadsDestDir + '/' + appid + '/'; - var target_path = config.uploadsDestDir + '/' + appid + '/' + filename; - var thumb_dir = config.uploadsDestDir + '/' + appid + '/thumbnail/'; - var thumb_path = config.uploadsDestDir + '/' + appid + '/thumbnail/' + filename; - - //Get the params for cropping an image - var x1 = req.body.x1, y1 = req.body.y1, x2 = req.body.x2, y2 = req.body.y2, height = req.body.height, width = req.body.width, filepath = target_path; - - if (!width) { - width = 100; - } - - //Dev logger - console.log(x1, x2, y1, y2, height, width, thumb_path); - console.log(String('Target Path: ' + target_path).warn); - console.log(String('Target Dir: ' + target_dir).warn); - console.log(String('Temp Path: ' + tmp_path).warn); - - //Create the directory and move the file to that directory - fs.mkdir(target_dir, 0777, function (e) { - - //Rename the file - fs.rename(tmp_path, target_path, function (err) { - if (err) { - console.error('File Rename Error:', err); - } - ; - - //Create the thumbnail from the default image - var imgOptions = { - src: target_path, - dst: thumb_path, - width: width, - height: height, - quality: 100, - x: x1, - y: y1 - }; - - //Create the thumb directory and resize the image - fs.mkdir(thumb_dir, 0777, function (e) { - //Resize the image - easyimg.resize(imgOptions, function (e) { - console.log('easyimg', e); - }); - }); - //unlink the file - fs.unlink(tmp_path, function () { - if (err) { - console.error('File Unlink Error: ', err); - - } else { - - //set the new path on the file - req.files.file.target_dir = target_dir; - req.files.file.target_path = target_path; - req.files.file.thumb_path = thumb_path; - req.files.file.thumb_dir = thumb_dir; - - req.files.file.filename = filename; - - //build the response object - var json = { - status: true, - filename: filename, - msg: 'File Uploaded', - results: req.files, - appid: appid - }; - res.send(json); - } - }); - }); - }); - }, //### get //I handle gathering records dynamically from a call to the v2 api. get: function (req, res, next) { - console.warn('find all', req.params.collection); - _ds.findAll(req.params.collection).then(function(data){ - res.send(data); - }, function(err){ - res.send(err); - }); + if (req.param('id')) { + console.log('find one', req.params.id); + _ds.findOne(req.params.collection, req.params.id).then(function (data) { + res.send(data); + }, function (err) { + res.send(err); + }); + } else { + _ds.findAll(req.params.collection).then(function (data) { + res.send(data); + }, function (err) { + res.send(err); + }); + } }, //### add //I handle adding a record to the database. add: function (req, res, next) { - _ds.create(req.params.collection, req.body).then(function(data){ - console.warn( 'create', data); + _ds.create(req.params.collection, req.body).then(function (data) { + console.warn('create', data); res.send(data); - }, function(err){ + }, function (err) { res.send(err); }); }, @@ -508,10 +364,10 @@ var RestResource = { edit: function (req, res, next) { var data = req.body; delete data._id; - _ds.update(req.params.collection, req.params.id, data).then(function(data){ + _ds.update(req.params.collection, req.params.id, data).then(function (data) { console.warn(data); res.send(data); - }, function(err){ + }, function (err) { res.send(err); }); }, @@ -522,108 +378,40 @@ var RestResource = { //### destroy //I handle destroy: function (req, res, next) { - _ds.destroy(req.params.collection, req.params.id).then(function(data){ + _ds.destroy(req.params.collection, req.params.id).then(function (data) { console.warn(data); res.send(data); - }, function(err){ + }, function (err) { res.send(err); }); }, - //### cloudupload - //I handle - cloudupload: function (req, res, next) { - var appid = null, results = null; - if (req.param('appid')) { - appid = String(req.param('appid')); - } - - console.log(req.files); - - }, - /* - * flavorize - Changes JSON based on flavor in configuration - */ - flavorize: function (flavor, doc, direction) { - if (direction == "in") { - switch (flavor) { - case "sproutcore": - delete doc['guid']; - // only do this in case flavor is set to sproutcore - break; - case "nounderscore": - delete doc['id']; - // only do this in case flavor is set to sproutcore - break; - default: - break; - } - } else { - switch (flavor) { - case "sproutcore": - var guid = doc._id.toHexString(); - delete doc['_id']; - doc.guid = guid; - break; - case "nounderscore": - var id = doc._id.toHexString(); - delete doc['_id']; - doc.id = id; - break; - default: - doc._id = doc._id.toHexString(); - break; + readme: function (res, req) { + var localPath = __dirname + '/../README.md'; + fs.readFile(localPath, 'utf8', function (err, data) { + if (err) { + req.end('There was an error.'); + return console.log(err); + } else { + req.writeHead(200, { + "Content-Type": 'utf8', + "Content-Length": data.length + }); + req.end(data); } - } - return doc; + console.log(data); + }); + }, + plugins: function (req, res) { + var result = fs.readdir('./app/cms-plugins', function (err, files) { + console.log(files); + res.header('Content-Type', 'application/json'); + res.jsonp(200, files); + }); } }; -//# Routes - -//### v2 API -//v2 mongo rest api -app.get('/api/v2', RestResource.v2index); -app.post('/api/v2/imagecrop', RestResource.imageCrop); -app.post('/api/v2/cloudupload', RestResource.cloudupload); -app.post('/api/v2/upload', RestResource.upload); -//Always users table -app.post('/api/v2/users/login', bodyParser.json(), RestResource.login); -app.post('/api/v2/users/register', bodyParser.json(), RestResource.register); -app.post('/api/v2/users/session', bodyParser.json(), RestResource.session); -//Dynamic REST -app.get('/api/v2/:db/:collection/:id?', RestResource.get); -app.post('/api/v2/:db/:collection', bodyParser.json(), RestResource.add); -app.put('/api/v2/:db/:collection/:id', bodyParser.json(), RestResource.edit); -app.delete('/api/v2/:db/:collection/:id', RestResource.destroy); - - -//Readme -var markdown = require("markdown").markdown; -app.get('/api/v2/README', function (res, req) { - var localPath = __dirname + '/../README.md'; - fs.readFile(localPath, 'utf8', function (err, data) { - if (err) { - req.end('There was an error.'); - return console.log(err); - } else { - req.writeHead(200, { - "Content-Type": 'utf8', - "Content-Length": data.length - }); - req.end(data); - } - console.log(data); - }); -}); -/* ======================[ @TODO: Other Rest Utility Methods ]====================== */ - -//### rackspaceUpload -//Upload a image file and create thumbnail and send to Rackspace Cloud Files. -function rackspaceUpload(localPath, targetPath, filename, cb) { - -}; //### getFile @@ -659,22 +447,6 @@ function writeFile(localPath, contents) { }); }; -//### modules -//Gather all of the files and folders in the app/modules directory -app.get('/api/v2/modules', function (req, res) { - var result = fs.readdir('./app/cms-content', function (err, files) { - console.log(files); - res.header('Content-Type', 'application/json'); - res.jsonp(200, files); - }); -}); - -//Write the pass.json file to the file system -app.get('/api/v2/smartpass/sign', function (req, res) { - var result = writeFile(req.params('path'), req.params('contents')); - res.header('Content-Type', 'application/json'); - res.jsonp(200, result); -}); var config = {}; @@ -682,48 +454,56 @@ var publicPath = config.publicDir; var uploadsTmpDir = config.uploadsTmpDir; var uploadDestDir = config.uploadDestDir; - -//Export to public api -exports.rest = { - RestResource: RestResource, - app: app, - express: express, - init: function (options) { - - console.log('email: admin@email.com '.verbose); - console.log('password: admin1234'.verbose) - - config = options; - - /* - */ - //### Express Config - //Configure the express app server. - app.configure(function () { - app.set("view options", {layout: false, pretty: true}); - - app.use(express.static(config.staticDir)); - app.use(express.directory(config.publicDir)); - - app.use(bodyParser.urlencoded({ extended: false })); - // parse application/json - app.use(bodyParser.json()); - - app.use("jsonp callback", true); - app.use('/api/upload', upload.fileHandler()); - - - app.use(function (req, res, next) { - console.log('%s %s', req.method, req.body, req.url); - next(); - }); - }); - - - app.listen(options.port || process.env.PORT, function () { - console.log(String('Node.js REST server listening on port: ' + options.port).verbose); +var cmsRest = function (options) { + "use strict"; + + var app = express(); + + console.warn('cmsRest - options', options); + console.log('email: admin@email.com '.verbose); + console.log('password: admin1234'.verbose) + config = options; + + + //### Express Config + //Configure the express app server. + //### modules + //Gather all of the files and folders in the app/modules directory + app.get(config.apiBase + '/plugins', RestResource.plugins); + //# Routes + //### v2 API + app.get(config.apiBase + '/readme', RestResource.readme); + //v2 mongo rest api + app.get(config.apiBase, RestResource.index); + app.post(config.apiBase + '/upload', RestResource.upload); + + //Always users table + app.post(config.apiBase + '/login', bodyParser.json(), RestResource.login); + app.post(config.apiBase + '/register', bodyParser.json(), RestResource.register); + app.post(config.apiBase + '/session', bodyParser.json(), RestResource.session); + + //Dynamic REST + app.get(config.apiBase + '/:collection/:id?', RestResource.get); + app.post(config.apiBase + '/:collection', bodyParser.json(), RestResource.add); + app.put(config.apiBase + '/:collection/:id', bodyParser.json(), RestResource.edit); + app.delete(config.apiBase + '/:collection/:id', RestResource.destroy); + + + app.configure(function () { + app.set("view options", {layout: false, pretty: true}); + app.use(express.static(config.staticDir)); + app.use(express.directory(config.publicDir)); + app.use(bodyParser.urlencoded({extended: false})); + app.use(bodyParser.json()); + app.use("jsonp callback", true); + app.use(config.apiBase + '/upload2', upload.fileHandler()); + app.use(function (req, res, next) { + console.warn(req.param('db'), req.param('collection')) + console.log('%s %s', req.method, req.body, req.url); + next(); }); - - return app; - } + }); + return app; }; + +module.exports = cmsRest; diff --git a/server.js b/server.js index 21d21fe..cfb3314 100755 --- a/server.js +++ b/server.js @@ -4,9 +4,9 @@ */ var fs = require('fs'), util = require('util'), - httpProxy = require('http-proxy'); + httpProxy = require('http-proxy'), + colors = require('colors'); -var colors = require('colors'); colors.setTheme({ silly: 'rainbow', input: 'grey', @@ -20,19 +20,6 @@ colors.setTheme({ error: 'red' }); -/* - console.log("this is an silly".silly); - console.log("this is an input".input); - console.log("this is an verbose".verbose); - console.log("this is an prompt".prompt); - console.log("this is an info".info); - console.log("this is an data".data); - console.log("this is an help".help); - console.log("this is an debug".debug); - console.log("this is an error".error); - console.log("this is a warning".warn); - */ - /** * @TODO - HTTPS Key and Cert * @@ -68,17 +55,25 @@ var options = { * @TODO - Externalize configuration for server and proxy, mongodb */ var config = JSON.parse(fs.readFileSync('./config/config.json')); +var cmsAuth = require('./routes/cms-auth'); +var cmsRest = require('./routes/rest'); + +var rest = new cmsRest(config); +var auth = new cmsAuth(config, rest); + +auth.listen(config.port || process.env.PORT, function () { + console.log(String('Node.js REST server listening on port: ' + config.port).verbose); +}); -//Dynamic rest server -var rest = require('./routes/rest').rest; //Socket server var socket = require('./routes/socketserver').SocketServer; //Initialize socket server and rest server -socket.init( - rest.init(config) -); +socket.init(auth); + + + //Create proxy server and proxy requests @@ -115,46 +110,3 @@ proxyServer = httpProxy.createServer(options, function (req, res, proxy) { //Start the proxy server proxyServer.listen(options.port); - - -/** - * Test Email - */ -var email = require("emailjs"); -var server = email.server.connect({ - user: config.email.username, - password: config.email.password, - host: "smtp.gmail.com", - ssl: false -}); - -var message = { - text: "i hope this works", - from: "you ", - to: "jonniespratley ", - cc: "angular.cms ", - subject: "testing angular-cms emailjs", - attachment: [ - {data: "i hope this works!", alternative: true} - // {path:"path/to/file.zip", type:"application/zip", name:"renamed.zip"} - ] -}; - -// send the message and get a callback with an error or details of the message that was sent -//server.send(message, function(err, message) { console.log(err || message); }); - -// you can continue to send more messages with successive calls to 'server.send', -// they will be queued on the same smtp connection - -// or you can create a new server connection with 'email.server.connect' -// to asynchronously send individual emails instead of a queue - - -/* - * fs.readFile(req.files.displayImage.path, function (err, data) { - // ... - var newPath = __dirname + "/uploads/uploadedFileName"; - fs.writeFile(newPath, data, function (err) { - res.redirect("back"); - }); - });*/ From 15d488a0f3c7b2d3f6bc3a6742a598ca3124a9c9 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 17:25:35 -0800 Subject: [PATCH 08/39] updated aut --- config/config.json | 1 + package.json | 3 + routes/cms-auth.js | 168 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 1 deletion(-) diff --git a/config/config.json b/config/config.json index ae12d79..c71b0f8 100644 --- a/config/config.json +++ b/config/config.json @@ -4,6 +4,7 @@ "apiBase": "/api/v2", "version": "v2", "security": {"salt": ""}, + "mongodb": "angularcms:angularcms@paulo.mongohq.com:10089/app19632340", "db": { "name": "angular-cms", "username": "amadmin", diff --git a/package.json b/package.json index 853cc0f..ef039a2 100755 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ "body-parser": "^1.9.3", "body-parser-json": "^1.9.2", "colors": "~0.6.2", + "connect-flash": "^0.1.1", + "cookie-parser": "^1.3.3", "easyimage": "~0.1.6", "emailjs": "~0.3.6", "express": "~3.4.6", @@ -44,6 +46,7 @@ "npmlog": "^0.1.1", "passport": "^0.2.1", "passport-google": "^0.3.0", + "passport-local": "^1.0.0", "promised-io": "~0.3.4", "request": "~2.34.0", "socket.io": "~0.9.16" diff --git a/routes/cms-auth.js b/routes/cms-auth.js index b7944a5..51f7fb4 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -1 +1,167 @@ -var passport = require('passport'), GoogleStrategy = require('passport-google').Strategy, log = require('npmlog'); var cmsAuth = function (options, app) { if (!app) { throw new Error('Must provide express application!'); } console.warn('cmsAuth', options); var baseUrl = options.host + ':' + options.port; var authed = function(req, res, next) { if (req.isAuthenticated()) { return next(); } else { res.json(503, { error: "service_unavailable", reason: "authentication_unavailable" }); } }; //Setup app.use(passport.initialize()); app.use(passport.session()); app.all('*', function(req, res, next){ console.warn('cmsAuth', req.params); next(); }); app.get('/api/user', authed, function(req, res){ res.json(req.user); }); app.get('/auth/google/:return?', passport.authenticate('google', { successRedirect: baseUrl }) ); app.get('/auth/logout', function(req, res){ req.logout(); res.redirect(options.apiBase); }); passport.use(new GoogleStrategy({ returnURL: baseUrl + '/auth/google/return', realm: baseUrl }, function (identifier, profile, done) { profile.identifier = identifier; return done(null, profile); })); passport.serializeUser(function (user, done) { done(null, user.identifier); }); passport.deserializeUser(function (id, done) { done(null, {identifier: id}); }); return app; }; module.exports = cmsAuth; \ No newline at end of file +var passport = require('passport'), + express = require('express'), + LocalStrategy = require('passport-local').Strategy, + GoogleStrategy = require('passport-google').Strategy, + log = require('npmlog'), + flash = require('connect-flash'), + DS = require('jps-ds').DS; +var cookieParser = require('cookie-parser'); + +function cmsAuth(options, app) { + var self = this; + if (!app) { + throw new Error('Must provide express application!'); + } + + console.warn('cmsAuth', options); + + self._ds = DS; + + var baseUrl = options.host + ':' + options.port; + var users = [ + {id: 1, username: 'bob', password: 'secret', email: 'bob@example.com'} + , {id: 2, username: 'joe', password: 'birthday', email: 'joe@example.com'} + ]; + + function findById(id, fn) { + var idx = id - 1; + console.log('findById', id); + if (users[idx]) { + + fn(null, users[idx]); + } else { + fn(new Error('User ' + id + ' does not exist')); + } + } + + function findByUsername(username, fn) { + console.log('findByUsername', username); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.username === username) { + return fn(null, user); + } + } + return fn(null, null); + } + +// Simple route middleware to ensure user is authenticated. +// Use this route middleware on any resource that needs to be protected. If +// the request is authenticated (typically via a persistent login session), +// the request will proceed. Otherwise, the user will be redirected to the +// login page. + function ensureAuthenticated(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + res.redirect('/auth/login'); + } + +// Passport session setup. +// To support persistent login sessions, Passport needs to be able to +// serialize users into and deserialize users out of the session. Typically, +// this will be as simple as storing the user ID when serializing, and finding +// the user by ID when deserializing. + passport.serializeUser(function (user, done) { + done(null, user.id); + }); + + passport.deserializeUser(function (id, done) { + findById(id, function (err, user) { + done(err, user); + }); + }); + + +// Use the LocalStrategy within Passport. +// Strategies in passport require a `verify` function, which accept +// credentials (in this case, a username and password), and invoke a callback +// with a user object. In the real world, this would query a database; +// however, in this example we are using a baked-in set of users. + passport.use(new LocalStrategy(function (username, password, done) { + // asynchronous verification, for effect... + process.nextTick(function () { + + // Find the user by username. If there is no user with the given + // username, or the password is not correct, set the user to `false` to + // indicate failure and set a flash message. Otherwise, return the + // authenticated `user`. + findByUsername(username, function (err, user) { + if (err) { + return done(err); + } + if (!user) { + return done(null, false, {message: 'Unknown user ' + username}); + } + if (user.password != password) { + return done(null, false, {message: 'Invalid password'}); + } + return done(null, user); + }) + }); + } + )); + + passport.use(new GoogleStrategy({ + returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/auth' + }, + function (identifier, profile, done) { + profile.identifier = identifier; + return done(null, profile); + } + )); + + + //Setup + app.configure(function () { + app.set('views', __dirname + '/www'); + app.use(flash()); + app.use(cookieParser); + app.use(passport.initialize()); + app.use(passport.session()); + + app.use(express.session({secret: 'angular-cms'})); + }); + app.all('*', function (req, res, next) { + console.warn('cmsAuth', req.params); + next(); + }); + app.get('/auth', function (req, res) { + if (!req.user) { + // res.json(200, {message: 'Please login'}); + res.render('login', { user: req.user, message: req.flash('error') }); + } + }); + + app.get('/account', ensureAuthenticated, function (req, res) { + res.json(200, {user: req.user}); + }); + + app.get('auth/login', function (req, res) { + res.render('login', { user: req.user, message: req.flash('error') }); + }); + app.get('/auth/user', ensureAuthenticated, function (req, res) { + res.json(200, req.user); + }); + app.get('/auth/google/:return?', passport.authenticate('google', {successRedirect: '/auth/account'})); + app.get('/auth/logout', function (req, res) { + req.logout(); + res.redirect(options.apiBase); + }); + app.get('/auth/logout', function (req, res) { + req.logout(); + res.redirect('/'); + }); + + + + app.post('/auth/login', + passport.authenticate('local', { failureRedirect: '/auth/login', failureFlash: true }), + function(req, res) { + res.redirect('/'); + }); + return app; +}; + + +module.exports = cmsAuth; From 5709abebe5949ec4388531b3107c964d552242c8 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 17:47:07 -0800 Subject: [PATCH 09/39] added some views --- .DS_Store | Bin 6148 -> 0 bytes package.json | 3 +++ routes/cms-auth.js | 61 +++++++++++++++++++++++++++------------------ www/account.ejs | 3 +++ www/index.ejs | 6 +++++ www/layout.ejs | 26 +++++++++++++++++++ www/login.ejs | 25 +++++++++++++++++++ 7 files changed, 100 insertions(+), 24 deletions(-) delete mode 100644 .DS_Store create mode 100644 www/account.ejs create mode 100644 www/index.ejs create mode 100644 www/layout.ejs create mode 100644 www/login.ejs diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index ccac949f6256a23e91da77b305df68633fab0ce2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~&x_MQ6vyAR)lICr5fpa8!{EhBk=E|EyC4{96~T*;#XY!ElTFzM(oASmd&owE zCx5Jeg&>H6e~DM|;ve9D;hP_=DRse%;>tXj`M#MqFF!s*W-t9Hz zTsd`m#V`%y?A~q=`E1%@lgJ-GbOvnd1b*LhM~{S`xXEPPaYrI@-%SP>5&jNiA^Ll2 z^lsoMgPygPrW?(6jb7j0%xW}kx9c^!(cH>1(=bizopI^PwHtSL+{5hYvs_XmxX1`Q zr*tOI(J6xm0Yu?J!`Wv;wfvCFKO;ld?fR2sAK>$y??)n4arVMboKY0A z=m6WZNth4P&Iu);X40sh(C62WtqEuXe~tiOA1D^Cw$faxSURv0M*!3cb_+wFpCxz> zRcb5ErD6n)$W&CBO4Jd9$aL(dYMiY!mnzeNh&$tT)SZbsp%8I*?5AQl5L>FQH33av zkw95CEx!NXKK}f_n50{pfF|%?5g?VW)9v6Zsl9dS<@jDpu{_4YjgQNviWIEWb}Sse e6|Z3thB3+=R9k5-6?@S1kAT3SD^1|968HgzouMfJ diff --git a/package.json b/package.json index ef039a2..2511767 100755 --- a/package.json +++ b/package.json @@ -31,8 +31,11 @@ "connect-flash": "^0.1.1", "cookie-parser": "^1.3.3", "easyimage": "~0.1.6", + "ejs": "^1.0.0", + "ejs-locals": "^1.0.2", "emailjs": "~0.3.6", "express": "~3.4.6", + "express-flash": "0.0.2", "http-proxy": "^1.3.0", "jps-ds": "~0.0.2", "jquery": "~2.1.0", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 51f7fb4..c5701f3 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -3,7 +3,8 @@ var passport = require('passport'), LocalStrategy = require('passport-local').Strategy, GoogleStrategy = require('passport-google').Strategy, log = require('npmlog'), - flash = require('connect-flash'), + path = require('path'), + flash = require('express-flash'), DS = require('jps-ds').DS; var cookieParser = require('cookie-parser'); @@ -114,32 +115,50 @@ function cmsAuth(options, app) { //Setup app.configure(function () { - app.set('views', __dirname + '/www'); - app.use(flash()); - app.use(cookieParser); - app.use(passport.initialize()); - app.use(passport.session()); + app.set('views', path.resolve(__dirname, '../www')); + app.set('view engine', 'ejs'); + app.engine('ejs', require('ejs-locals')); + app.use(express.logger()); + app.use(express.cookieParser()); + app.use(express.bodyParser()); + app.use(express.methodOverride()); + app.use(express.session({secret: 'angular-cms'})); + app.use(express.session({ cookie: { maxAge: 60000 }})); + app.use(flash()); + // Initialize Passport! Also use passport.session() middleware, to support + // persistent login sessions (recommended). + app.use(passport.initialize()); + app.use(passport.session()); + app.use(app.router); + - app.use(express.session({secret: 'angular-cms'})); }); + + + app.all('*', function (req, res, next) { console.warn('cmsAuth', req.params); next(); }); - app.get('/auth', function (req, res) { - if (!req.user) { - // res.json(200, {message: 'Please login'}); - res.render('login', { user: req.user, message: req.flash('error') }); - } - }); - app.get('/account', ensureAuthenticated, function (req, res) { - res.json(200, {user: req.user}); + app.get('/', function(req, res){ + + res.render('index', { user: req.user }); }); - app.get('auth/login', function (req, res) { - res.render('login', { user: req.user, message: req.flash('error') }); - }); +app.get('/account', ensureAuthenticated, function(req, res){ + res.render('account', { user: req.user }); +}); + +app.get('/login', function(req, res){ + res.render('login', { user: req.user, message: 'Please login' }); +}); +app.post('/login', passport.authenticate('local', { failureRedirect: '/login', failureFlash: false }), function(req, res) { + res.redirect('/'); +}); + + + app.get('/auth/user', ensureAuthenticated, function (req, res) { res.json(200, req.user); }); @@ -154,12 +173,6 @@ function cmsAuth(options, app) { }); - - app.post('/auth/login', - passport.authenticate('local', { failureRedirect: '/auth/login', failureFlash: true }), - function(req, res) { - res.redirect('/'); - }); return app; }; diff --git a/www/account.ejs b/www/account.ejs new file mode 100644 index 0000000..d69ad21 --- /dev/null +++ b/www/account.ejs @@ -0,0 +1,3 @@ +<% layout('layout') -%> +

Username: <%= user.username %>

+

Email: <%= user.email %>

\ No newline at end of file diff --git a/www/index.ejs b/www/index.ejs new file mode 100644 index 0000000..e70df3e --- /dev/null +++ b/www/index.ejs @@ -0,0 +1,6 @@ +<% layout('layout') -%> +<% if (!user) { %> +

Welcome! Please log in.

+<% } else { %> +

Hello, <%= user.username %>.

+<% } %> diff --git a/www/layout.ejs b/www/layout.ejs new file mode 100644 index 0000000..264c217 --- /dev/null +++ b/www/layout.ejs @@ -0,0 +1,26 @@ + + + + + + Passport-Local Example + + + +
+ <% if (!user) { %> +

+ Home | + Log In +

+ <% } else { %> +

+ Home | + Account | + Log Out +

+ <% } %> + <%- body %> +
+ + diff --git a/www/login.ejs b/www/login.ejs new file mode 100644 index 0000000..a9fd22b --- /dev/null +++ b/www/login.ejs @@ -0,0 +1,25 @@ + +<% layout('layout') -%> +
+ +<% if (message) { %> +

<%= message %>

+<% } %> + + +
+
+ +
+
+
+ + +
+
+ +
+
+

Hint - bob:secret

+ +
From d9f1441522ae3e2dd9da44d2a8e45ee600a32296 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 18:34:10 -0800 Subject: [PATCH 10/39] updated ui --- package.json | 3 + routes/cms-auth.js | 207 ++++++++----- routes/rest.js | 2 + www/layout.ejs | 18 +- www/login.ejs | 43 ++- www/main.css | 713 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 891 insertions(+), 95 deletions(-) create mode 100644 www/main.css diff --git a/package.json b/package.json index 2511767..255e47a 100755 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "emailjs": "~0.3.6", "express": "~3.4.6", "express-flash": "0.0.2", + "express-session": "^1.9.3", "http-proxy": "^1.3.0", "jps-ds": "~0.0.2", "jquery": "~2.1.0", @@ -48,8 +49,10 @@ "mongoose": "*", "npmlog": "^0.1.1", "passport": "^0.2.1", + "passport-facebook": "^1.0.3", "passport-google": "^0.3.0", "passport-local": "^1.0.0", + "passport-twitter": "^1.0.2", "promised-io": "~0.3.4", "request": "~2.34.0", "socket.io": "~0.9.16" diff --git a/routes/cms-auth.js b/routes/cms-auth.js index c5701f3..518a1ea 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -6,7 +6,64 @@ var passport = require('passport'), path = require('path'), flash = require('express-flash'), DS = require('jps-ds').DS; + + +var session = require('express-session') var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); + +var users = [ + {id: 1, username: 'admin', password: 'admin', email: 'admin@gmail.com'}, + {id: 2, username: 'test', password: 'test', email: 'test@gmail.com'}, + {id: 3, username: 'jonniespratley', password: 'fred', email: 'jonniespratley@gmail.com'} + +]; + + +var User = function(){ + +}; + +User.findOrCreate = function(profile, fn){ + console.warn('findOrCreate', profile); + User.findByEmail(profile.emails[0], function(err, user){ + fn(user); + }); +}; +User.findById = function(id, fn) { + var idx = id - 1; + console.warn('findById', id); + if (users[idx]) { + fn(null, users[idx]); + } else { + fn(new Error('User ' + id + ' does not exist')); + } +} + +User.findByUsername = function(username, fn) { + console.warn('findByUsername', username); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.username === username) { + return fn(null, user); + } + } + return fn(null, null); +} + +User.findByEmail = function(email, fn) { + console.warn('findByEmail', email); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.email === email) { + return fn(null, user); + } + } + return fn(null, null); +} + + + function cmsAuth(options, app) { var self = this; @@ -19,32 +76,15 @@ function cmsAuth(options, app) { self._ds = DS; var baseUrl = options.host + ':' + options.port; - var users = [ - {id: 1, username: 'bob', password: 'secret', email: 'bob@example.com'} - , {id: 2, username: 'joe', password: 'birthday', email: 'joe@example.com'} - ]; - - function findById(id, fn) { - var idx = id - 1; - console.log('findById', id); - if (users[idx]) { - - fn(null, users[idx]); - } else { - fn(new Error('User ' + id + ' does not exist')); - } - } - function findByUsername(username, fn) { - console.log('findByUsername', username); - for (var i = 0, len = users.length; i < len; i++) { - var user = users[i]; - if (user.username === username) { - return fn(null, user); - } - } - return fn(null, null); - } + + + + + + + + // Simple route middleware to ensure user is authenticated. // Use this route middleware on any resource that needs to be protected. If @@ -55,7 +95,7 @@ function cmsAuth(options, app) { if (req.isAuthenticated()) { return next(); } - res.redirect('/auth/login'); + res.redirect('/login'); } // Passport session setup. @@ -63,17 +103,17 @@ function cmsAuth(options, app) { // serialize users into and deserialize users out of the session. Typically, // this will be as simple as storing the user ID when serializing, and finding // the user by ID when deserializing. - passport.serializeUser(function (user, done) { - done(null, user.id); - }); - - passport.deserializeUser(function (id, done) { - findById(id, function (err, user) { - done(err, user); - }); - }); + passport.serializeUser(function(user, done) { + done(null, user.id); +}); +passport.deserializeUser(function(id, done) { + User.findById(id, function(err, user) { + done(err, user); + }); +}); +/* // Use the LocalStrategy within Passport. // Strategies in passport require a `verify` function, which accept // credentials (in this case, a username and password), and invoke a callback @@ -102,34 +142,43 @@ function cmsAuth(options, app) { }); } )); - + */ +/**/ passport.use(new GoogleStrategy({ - returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/auth' + returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' }, function (identifier, profile, done) { - profile.identifier = identifier; - return done(null, profile); + console.warn( 'googleCallback', profile); + profile.openId = identifier; + User.findOrCreate(profile, function(err, user) { + done(err, user); + }); } )); //Setup app.configure(function () { - app.set('views', path.resolve(__dirname, '../www')); - app.set('view engine', 'ejs'); - app.engine('ejs', require('ejs-locals')); - app.use(express.logger()); - app.use(express.cookieParser()); - app.use(express.bodyParser()); - app.use(express.methodOverride()); - app.use(express.session({secret: 'angular-cms'})); - app.use(express.session({ cookie: { maxAge: 60000 }})); - app.use(flash()); - // Initialize Passport! Also use passport.session() middleware, to support - // persistent login sessions (recommended). - app.use(passport.initialize()); - app.use(passport.session()); - app.use(app.router); + app.use(express.logger()); + 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(express.cookieParser()); + app.use(express.methodOverride()); + app.use(bodyParser.urlencoded({extended: false})); + app.use(bodyParser.json()); + app.use("jsonp callback", true); + app.use(flash()); + app.use(session({ + secret: 'angular-cms', + resave: true, + saveUninitialized: true + })); + app.use(passport.initialize()); + app.use(passport.session()); + + app.use(app.router); }); @@ -142,31 +191,57 @@ function cmsAuth(options, app) { }); app.get('/', function(req, res){ - - res.render('index', { user: req.user }); + 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('/account', ensureAuthenticated, function(req, res){ + res.render('account', { user: req.user }); + }); -app.get('/login', function(req, res){ - res.render('login', { user: req.user, message: 'Please login' }); -}); -app.post('/login', passport.authenticate('local', { failureRedirect: '/login', failureFlash: false }), function(req, res) { - res.redirect('/'); -}); + app.get('/login', function(req, res){ + res.render('login', { user: req.user, message: 'Please login', status: 'warning' }); + }); + app.post('/login', function(req, res, next) { + passport.authenticate('local', function(err, user, info) { + if (err) { + return next(err) + } + if (!user) { + //req.flash('error', info.message); + return res.redirect('/login') + } + req.logIn(user, function(err) { + if (err) { + return next(err); + } + return res.redirect('/users/' + user.username); + }); + })(req, res, next); + }); app.get('/auth/user', ensureAuthenticated, function (req, res) { res.json(200, req.user); }); - app.get('/auth/google/:return?', passport.authenticate('google', {successRedirect: '/auth/account'})); + app.get('/auth/logout', function (req, res) { req.logout(); res.redirect(options.apiBase); }); + + + // Redirect the user to Google for authentication. When complete, Google +// will redirect the user back to the application at +// /auth/google/return +app.get('/auth/google', passport.authenticate('google')); + +// Google will redirect the user to this URL after authentication. Finish +// the process by verifying the assertion. If valid, the user will be +// logged in. Otherwise, authentication has failed. +app.get('/auth/google/return', + passport.authenticate('google', { successRedirect: '/', + failureRedirect: '/login' })); app.get('/auth/logout', function (req, res) { req.logout(); res.redirect('/'); diff --git a/routes/rest.js b/routes/rest.js index 6045035..b95fc91 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -497,6 +497,8 @@ var cmsRest = function (options) { app.use(bodyParser.json()); app.use("jsonp callback", true); app.use(config.apiBase + '/upload2', upload.fileHandler()); + + app.use(app.router); app.use(function (req, res, next) { console.warn(req.param('db'), req.param('collection')) console.log('%s %s', req.method, req.body, req.url); diff --git a/www/layout.ejs b/www/layout.ejs index 264c217..4fb627b 100644 --- a/www/layout.ejs +++ b/www/layout.ejs @@ -2,25 +2,15 @@ - Passport-Local Example + + +
- <% if (!user) { %> -

- Home | - Log In -

- <% } else { %> -

- Home | - Account | - Log Out -

- <% } %> - <%- body %> + <%- body %>
diff --git a/www/login.ejs b/www/login.ejs index a9fd22b..22c00ee 100644 --- a/www/login.ejs +++ b/www/login.ejs @@ -1,25 +1,38 @@ <% layout('layout') -%>
+
+ + +
-
-
- -
-
-
- - -
-
- -
-
-

Hint - bob:secret

diff --git a/www/main.css b/www/main.css new file mode 100644 index 0000000..97c1555 --- /dev/null +++ b/www/main.css @@ -0,0 +1,713 @@ +.form-list{ + +} + +.form-list select{ + width:75px; +} + +.navbar-avatar{ + height: 20px; +} +.actions { + width: 100px; + text-align: center; +} + +.aside { + width: 320px; + z-index: 5000; + background: #fff; + position: fixed; + overflow: auto; + min-width: 320px; + top: 0; + display: block; + bottom: 0; +} + +/* @group Global */ + +#dashboard:-webkit-full-screen { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + padding: 10px 15px; + background: none; +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + padding-top: 65px; +} + +button.navbar-toggle { + +} + +.login .login-wrap { + margin: 5px auto; + max-width: 315px; +} + +footer { + font-size: .8em; + padding: 30px 0; + text-align: center; + margin-top: 45px; + display: block; + text-transform: none; +} + +h2 { + margin-top: 5px; +} + +html { + overflow-x: hidden; +} + +.app { + clear: both; + display: block; + moz-transition: width 1s ease-in-out, left 1.5s ease-in-out; + o-transition: width 1s ease-in-out, left 1.5s ease-in-out; + transition: width 1s ease-in-out, left 1.5s ease-in-out; + webkit-transition: width 1s ease-in-out, left 1.5s ease-in-out; + width: 100%; +} + +.avatar img { + max-height: 100px; +} + +/* @end */ + +/* @group Animate */ + +.view-animate { + padding-left: 35px; +} + +.view-animate.ng-enter { + opacity: .5; + top: 100%; +} + +.view-animate.ng-enter, +.view-animate.ng-leave { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) .3s; + webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) .3s; +} + +.view-animate.ng-enter.ng-enter-active { + opacity: 1; + top: 0; +} + +.view-animate.ng-leave.ng-leave-active { + opacity: 0; + top: -100%; +} + +.view-animate-container { + min-height: 450px; + overflow: hidden; + position: relative; +} + +.animate-if { + display: block; +} + +.animate-if.ng-enter, .animate-if.ng-leave { + transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; + webkit-transition: all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.3s; +} + +.animate-if.ng-enter, .animate-if.ng-leave.ng-leave-active { + opacity: 0; +} + +.animate-if.ng-leave, .animate-if.ng-enter.ng-enter-active { + opacity: 1; +} + +/* @end */ + +/* @group Sidebar */ + +.cms-sidebar { + moz-transition: width .5s ease-in-out, left 1.5s ease-in-out; + o-transition: width .5s ease-in-out, left 1.5s ease-in-out; + transition: width .5s ease-in-out, left 1.5s ease-in-out; + webkit-transition: width .5s ease-in-out, left 1.5s ease-in-out; + display: block; + + z-index: 150; + top: 0; +} + +.cms-sidebar.closed { + display: block; + width: 85px; +} +.cms-sidebar.closed .well{ + width: 45px; + +} + +.cms-sidebar.closed span.title { + display: none; + overflow: hidden; +} + +.cms-sidebar.closed .nav-header { + display: none; +} + +.cms-sidebar-nav, .cms-sidebar span.title { + padding: 0; + moz-transition: width .5s ease-in-out; + o-transition: width .5s ease-in-out; + transition: width .5s ease-in-out; + webkit-transition: width .5s ease-in-out; +} + +.cms-sidebar-nav .nav .nav-header { + color: #999; + font-size: 11px; + font-weight: bold; + padding: 8px 10px; + text-transform: uppercase; +} + +.cms-sidebar-nav li a { + display: block; + white-space: nowrap; +} + +.cms-sidebar-nav.fixed { + border-radius: 0px; + left: 0; + position: fixed; + top: 52px; +} + +.cms-sidebar-nav-toggle:hover { + +} + +.cms-sidebar-nav-toggle { + z-index: 200; + white-space: nowrap; +} + +.avatar { + margin: 25px auto; +} + +.slim-view { + max-width: 310px; + margin: 15px auto; +} +/* @end */ + +/* + +@group Themes */ + +.cms-themes .theme img { + opacity: .8; +} + +.cms-themes .theme img:hover, .cms-themes .theme.selected img { + opacity: 1; +} + +/* @end */ + +/* @group Custom */ + +.hero-unit { + background-color: #eee; + border-radius: 6px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + margin: 50px auto 0 auto; + overflow: hidden; + padding: 60px; + width: 300px; +} + +.hero-unit h1 { + font-size: 60px; + letter-spacing: -1px; + line-height: 1; +} + +.feature { + margin: 5px 10px; +} + +.highlight { + border: 5px solid #6f0; +} + +.highlight, .unhighlight { + border-radius: 5px; + margin: 10px; + max-height: 100px; + max-width: 100px; + moz-border-radius: 5px; + webkit-border-radius: 5px; +} + +.jumbotron { + text-align: center; +} + +.jumbotron h1 { + margin-top: 5px; +} + +.login .alert { + text-align: center; +} + +.login .img-logo { + margin: 15px auto; + max-width: 275px; +} + +.login .login-view { + margin: 55px auto; + max-width: 280px; +} + +.login .well { + border-radius: 2px; + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + moz-border-radius: 2px; + moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + webkit-border-radius: 2px; + webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); +} + + +.login, .form-login, .form-forgot { + +} + +.drop-container { + border: 3px dashed #ccc; + color: #999; + margin-bottom: 25px; + padding: 55px; + text-align: center; +} + +.drop-container h4 { + font-size: 180%; +} + +.placeholder { + background: #eee; + border: 1px dashed #ccc; + border-radius: 4px; + color: #999; + margin: 5px; + padding: 10px; +} + +/* @end */ + +/* @group Utils */ + +.display-block { + display: block; +} + +.em { + font-style: italic; +} + +.fl { + float: right !important; +} + +.fr { + float: right !important; +} + +.margin { + margin: 10px !important; +} + +.margin-bottom { + margin-bottom: 10px !important; +} + +.margin-bottom-lg { + margin-bottom: 22px !important; +} + +.margin-bottom-none { + margin-bottom: 0 !important; +} + +.margin-bottom-sm { + margin-bottom: 5px !important; +} + +.margin-left { + margin-left: 10px !important; +} + +.margin-left-lg { + margin-left: 22px !important; +} + +.margin-left-none { + margin-left: 0 !important; +} + +.margin-left-sm { + margin-left: 5px !important; +} + +.margin-lg { + margin: 22px !important; +} + +.margin-none { + margin: 0 !important; +} + +.margin-right { + margin-right: 10px !important; +} + +.margin-right-lg { + margin-right: 22px !important; +} + +.margin-right-none { + margin-right: 0 !important; +} + +.margin-right-sm { + margin-right: 5px !important; +} + +.margin-sm { + margin: 5px !important; +} + +.margin-top { + margin-top: 10px !important; +} + +.margin-top-lg { + margin-top: 22px !important; +} + +.margin-top-none { + margin-top: 0 !important; +} + +.margin-top-sm { + margin-top: 5px !important; +} + +.ng-hide { + display: none !important; +} + +.no-link { + color: #333; +} + +.no-underline:hover { + text-decoration: none; +} + +.padding { + padding: 10px !important; +} + +.padding-bottom { + padding-bottom: 10px !important; +} + +.padding-bottom-lg { + padding-bottom: 22px !important; +} + +.padding-bottom-none { + padding-bottom: 0 !important; +} + +.padding-bottom-sm { + padding-bottom: 5px !important; +} + +.padding-left { + padding-left: 10px !important; +} + +.padding-left-lg { + padding-left: 22px !important; +} + +.padding-left-none { + padding-left: 0 !important; +} + +.padding-left-sm { + padding-left: 5px !important; +} + +.padding-lg { + padding: 22px !important; +} + +.padding-none { + padding: 0 !important; +} + +.padding-right { + padding-right: 10px !important; +} + +.padding-right-lg { + padding-right: 22px !important; +} + +.padding-right-none { + padding-right: 0 !important; +} + +.padding-right-sm { + padding-right: 5px !important; +} + +.padding-sm { + padding: 5px !important; +} + +.padding-top { + padding-top: 10px !important; +} + +.padding-top-lg { + padding-top: 22px !important; +} + +.padding-top-none { + padding-top: 0 !important; +} + +.padding-top-sm { + padding-top: 5px !important; +} + +.small { + font-size: 85%; +} + +.strong { + font-weight: bold; +} + +.sub-header { + border-bottom: 1px solid #eee; + padding-bottom: 10px; +} + +.tc { + text-align: center; +} + +.tl { + text-align: left; +} + +.tr { + text-align: right; +} + +.unhighlight { + border: 5px solid #ccc; +} + +.border-bottom-none { + border-bottom: none !important; +} + +.border-left-none { + border-left: none !important; +} + +.border-right-none { + border-right: none !important; +} + +.border-top-none { + border-top: none !important; +} + +.center { + text-align: center; +} + +.center { + text-align: center; +} + +.clickable { + cursor: pointer; +} + +/* @end */ + +/* @group Uploader */ + +.uploader-dropzone { + border: 2px dashed #ccc; + color: #999; + color: #bbb; + margin-bottom: 25px; + padding: 25px; + padding: 55px; + text-align: center; +} + +.uploader-dropzone h4 { + font-size: 180%; +} + +.uploader-thumb { + max-height: 450px; +} + +.uploader-thumbs li { + margin: 5px; +} + +.uploader-thumbs li a { + text-decoration: none; +} + +.uploader-thumbs li span { + text-align: center; +} + +/* @end */ + +/* @group Responsive */ + +@media (max-width: 480px) { + +html body { + padding-top: 35px !important; + padding-right: 20px !important; +} + +.view-animate { + padding-left: 15px; +} +.page-header h1 { + font-size: 200%; + margin-bottom: 0px; +} + + +} + +@media (max-width: 767px) { + +.cms-sidebar{ + margin-top: 20px; +} +html body { + padding: 55px 15px !important; + padding-left: 0; +} +.cms-sidebar { + width: 80px !important; +} +.page-header h1 { + font-size: 200%; + margin-bottom: 0px; +} +.cms-sidebar .well { + max-width: 65px; + position: fixed; + +} + +.cms-sidebar .title { + display: none; +} +.view-animate { + padding-left: 5px; +} +} + +@media (min-width: 768px) { + +.cms-sidebar .well { + width: 160px; + position: fixed; + +} + +.view-animate { + padding-left: 35px; +} + +} + +@media (min-width: 768px) and (max-width: 979px) { + +.view-animate { + padding-left: 25px; +} + + +} + +@media (min-width: 1200px) { + +.view-animate { + padding-left: 10px; +} + +} + +/* @end */ + +/* @group Panels */ + +.panel-body { + position: relative; + padding-bottom: 65px !important; +} + +.panel-footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +/* @end */ From 75ef3396084d2d887866672f60945921e1aa0ec3 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sat, 6 Dec 2014 22:08:01 -0800 Subject: [PATCH 11/39] updating protractor test --- Gruntfile.js | 20 ++++--- app/views/register.html | 12 ++-- karma-e2e.conf.js | 3 +- package.json | 2 + protractor.conf.js | 13 +++- routes/cms-auth.js | 120 +++++++++++++------------------------ routes/rest.js | 24 ++++---- test/e2e/app.coffee | 113 ++++++++++++++++++++++------------ test/protractor/App.coffee | 0 test/protractor/App.js | 53 ---------------- www/index.ejs | 5 ++ www/login.ejs | 13 ++++ 12 files changed, 176 insertions(+), 202 deletions(-) delete mode 100644 test/protractor/App.coffee delete mode 100644 test/protractor/App.js diff --git a/Gruntfile.js b/Gruntfile.js index 82fd306..1da0265 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -55,7 +55,7 @@ module.exports = function (grunt) { }, coffeeTest: { files: ['test/{,**/}*.{coffee,litcoffee,coffee.md}'], - tasks: ['coffee:test', 'newer:coffee:test', 'karma'] + tasks: ['coffee:test', 'newer:coffee:test', 'karma:unit', 'protractor'] }, compass: { files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], @@ -553,12 +553,12 @@ module.exports = function (grunt) { } }, + //Protractor webdriver & protractor protractor_webdriver: { - options: { - // Task-specific options go here. - }, test: { - // Target-specific file lists and/or options go here. + options: { + command: 'webdriver-manager start' + } } }, protractor: { @@ -575,6 +575,9 @@ module.exports = function (grunt) { } } }, + + + //Coveralls code coverage coveralls: { options: { debug: true, @@ -616,13 +619,14 @@ module.exports = function (grunt) { grunt.registerTask('test', function (target) { grunt.task.run(['clean:server', 'concurrent:test', 'autoprefixer', 'connect:test']); if (target === 'e2e') { - return grunt.task.run(['karma']); + return grunt.task.run(['karma', 'protractor_webdriver', 'protractor', 'coveralls']); + } else if(target === 'server'){ + return grunt.task.run(['coffee:test', 'mochaTest']); } else { return grunt.task.run(['karma:unit', 'coveralls']); } }); - grunt.registerTask('test:server', 'coffee:test', 'mochaTest'); - grunt.registerTask('test:protractor', 'coffee:test', 'protractor') + grunt.registerTask('build-docs', [ 'useminPrepare', 'autoprefixer', 'concat', 'ngmin']); grunt.registerTask('build', ['clean:dist', 'useminPrepare', 'concurrent:dist', 'autoprefixer', 'concat', 'ngmin', 'copy:dist', /*'cdnify',*/ 'cssmin', 'uglify', 'rev', 'usemin']); diff --git a/app/views/register.html b/app/views/register.html index 522b6f4..ad7e0bf 100755 --- a/app/views/register.html +++ b/app/views/register.html @@ -8,21 +8,21 @@
- +
- +
- +
-
@@ -36,4 +36,4 @@ Back to Login - \ No newline at end of file + diff --git a/karma-e2e.conf.js b/karma-e2e.conf.js index 9cc1431..4894a8e 100644 --- a/karma-e2e.conf.js +++ b/karma-e2e.conf.js @@ -15,7 +15,6 @@ module.exports = function(config) { ], preprocessors: { - 'test/e2e/*.coffee': ['coffee'], 'test/e2e/**/*.coffee': ['coffee'] }, @@ -47,7 +46,7 @@ module.exports = function(config) { // - Safari (only Mac) // - PhantomJS // - IE (only Windows) - browsers: ['Chrome'], + browsers: ['PhantomJS'], // Continuous Integration mode diff --git a/package.json b/package.json index 255e47a..51a5850 100755 --- a/package.json +++ b/package.json @@ -51,9 +51,11 @@ "passport": "^0.2.1", "passport-facebook": "^1.0.3", "passport-google": "^0.3.0", + "passport-http": "^0.2.2", "passport-local": "^1.0.0", "passport-twitter": "^1.0.2", "promised-io": "~0.3.4", + "q": "^1.1.2", "request": "~2.34.0", "socket.io": "~0.9.16" }, diff --git a/protractor.conf.js b/protractor.conf.js index a7ecb9c..1deb01a 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -9,16 +9,23 @@ exports.config = { 'browserName': 'chrome' }, + params: { + baseUrl: 'http://localhost:9000' + }, + // Spec patterns are relative to the current working directly when // protractor is called. specs: [ - '.tmp/protractor/*.js', - 'test/protractor/*.js' + '.tmp/protractor/*-spec.js', + 'test/protractor/*-spec.js' ], // Options to be passed to Jasmine-node. jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 30000 - } + }, + onPrepare: function(){ + browser.driver.get(browser.params.baseUrl); + } }; diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 518a1ea..0800198 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -1,9 +1,11 @@ var passport = require('passport'), express = require('express'), + BasicStrategy = require('passport-http').Strategy, LocalStrategy = require('passport-local').Strategy, GoogleStrategy = require('passport-google').Strategy, log = require('npmlog'), path = require('path'), + q = require('q'), flash = require('express-flash'), DS = require('jps-ds').DS; @@ -16,13 +18,9 @@ var users = [ {id: 1, username: 'admin', password: 'admin', email: 'admin@gmail.com'}, {id: 2, username: 'test', password: 'test', email: 'test@gmail.com'}, {id: 3, username: 'jonniespratley', password: 'fred', email: 'jonniespratley@gmail.com'} - ]; - -var User = function(){ - -}; +var User = function(){}; User.findOrCreate = function(profile, fn){ console.warn('findOrCreate', profile); @@ -38,19 +36,20 @@ User.findById = function(id, fn) { } else { fn(new Error('User ' + id + ' does not exist')); } -} - +}; User.findByUsername = function(username, fn) { + var defer = q.defer(); console.warn('findByUsername', username); for (var i = 0, len = users.length; i < len; i++) { var user = users[i]; if (user.username === username) { - return fn(null, user); + defer.resolve(user); + } else { + console.warn('user not found', username); } } - return fn(null, null); -} - + return defer.promise; +}; User.findByEmail = function(email, fn) { console.warn('findByEmail', email); for (var i = 0, len = users.length; i < len; i++) { @@ -60,31 +59,15 @@ User.findByEmail = function(email, fn) { } } return fn(null, null); -} - - - +}; function cmsAuth(options, app) { var self = this; + var baseUrl = options.host + ':' + options.port; if (!app) { throw new Error('Must provide express application!'); } - console.warn('cmsAuth', options); - - self._ds = DS; - - var baseUrl = options.host + ':' + options.port; - - - - - - - - - // Simple route middleware to ensure user is authenticated. // Use this route middleware on any resource that needs to be protected. If @@ -105,44 +88,37 @@ function cmsAuth(options, app) { // the user by ID when deserializing. passport.serializeUser(function(user, done) { - done(null, user.id); -}); + done(null, user.id); + }); + + passport.deserializeUser(function(id, done) { + User.findById(id, function(err, user) { + done(err, user); + }); + }); + + +/* */ -passport.deserializeUser(function(id, done) { - User.findById(id, function(err, user) { - done(err, user); - }); -}); -/* -// Use the LocalStrategy within Passport. // Strategies in passport require a `verify` function, which accept // credentials (in this case, a username and password), and invoke a callback // with a user object. In the real world, this would query a database; // however, in this example we are using a baked-in set of users. - passport.use(new LocalStrategy(function (username, password, done) { - // asynchronous verification, for effect... + passport.use(new LocalStrategy({ + usernameField: 'email', + passwordField: 'password' + }, function (username, password, done) { process.nextTick(function () { - - // Find the user by username. If there is no user with the given - // username, or the password is not correct, set the user to `false` to - // indicate failure and set a flash message. Otherwise, return the - // authenticated `user`. - findByUsername(username, function (err, user) { - if (err) { - return done(err); - } - if (!user) { - return done(null, false, {message: 'Unknown user ' + username}); - } - if (user.password != password) { - return done(null, false, {message: 'Invalid password'}); - } + console.warn('find by username'); + User.findByUsername(username).then(function(user){ return done(null, user); - }) + }, function(err){ + return done(null, false); + }); }); } )); - */ + /**/ passport.use(new GoogleStrategy({ returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' @@ -157,6 +133,7 @@ passport.deserializeUser(function(id, done) { )); + //Setup app.configure(function () { app.use(express.logger()); @@ -177,14 +154,15 @@ passport.deserializeUser(function(id, done) { })); app.use(passport.initialize()); app.use(passport.session()); - app.use(app.router); - - }); + 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(); @@ -202,24 +180,12 @@ passport.deserializeUser(function(id, done) { res.render('login', { user: req.user, message: 'Please login', status: 'warning' }); }); - app.post('/login', function(req, res, next) { - passport.authenticate('local', function(err, user, info) { - if (err) { - return next(err) - } - if (!user) { - //req.flash('error', info.message); - return res.redirect('/login') - } - req.logIn(user, function(err) { - if (err) { - return next(err); - } - return res.redirect('/users/' + user.username); - }); - })(req, res, next); - }); +app.post('/login', + passport.authenticate('local', { successRedirect: '/', + failureRedirect: '/login', + failureFlash: false }) +); app.get('/auth/user', ensureAuthenticated, function (req, res) { res.json(200, req.user); diff --git a/routes/rest.js b/routes/rest.js index b95fc91..9b33ce9 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -207,10 +207,10 @@ var RestResource = { console.log('Login Query: ', query); - _ds.findOne(req.params.collection, req.params.id).then(function (data) { - res.send(data); + _ds.findOne('users', query).then(function (data) { + res.json(200, data); }, function (err) { - res.send(err); + res.json(400, err); }); @@ -300,10 +300,6 @@ var RestResource = { //Resize the image easyimg.resize(imgOptions, function (e) { console.log('easyimg', imgOptions, e); - - - -//set the new path on the file req.files.file.target_dir = target_dir; req.files.file.target_path = target_path; req.files.file.thumb_path = thumb_path; @@ -478,15 +474,15 @@ var cmsRest = function (options) { app.post(config.apiBase + '/upload', RestResource.upload); //Always users table - app.post(config.apiBase + '/login', bodyParser.json(), RestResource.login); - app.post(config.apiBase + '/register', bodyParser.json(), RestResource.register); - app.post(config.apiBase + '/session', bodyParser.json(), RestResource.session); + app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); + app.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); + app.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); //Dynamic REST - app.get(config.apiBase + '/:collection/:id?', RestResource.get); - app.post(config.apiBase + '/:collection', bodyParser.json(), RestResource.add); - app.put(config.apiBase + '/:collection/:id', bodyParser.json(), RestResource.edit); - app.delete(config.apiBase + '/:collection/:id', RestResource.destroy); + app.get(config.apiBase + '/:db/:collection/:id?', RestResource.get); + app.post(config.apiBase + '/:db/:collection', bodyParser.json(), RestResource.add); + app.put(config.apiBase + '/:db/:collection/:id', bodyParser.json(), RestResource.edit); + app.delete(config.apiBase + '/:db/:collection/:id', RestResource.destroy); app.configure(function () { diff --git a/test/e2e/app.coffee b/test/e2e/app.coffee index 59e7062..73c3019 100644 --- a/test/e2e/app.coffee +++ b/test/e2e/app.coffee @@ -1,45 +1,74 @@ +###* + Helpers ### -MainPage view + +j$ = + el: (selector) -> + element(selector) + input: (name) -> + element("input[name='#{name}']") + + +###* +App Page ### -MainPage = - index: () -> +AppPage = () -> + @get = -> browser().navigateTo('/') -LoginPage = - get: () -> +###* + Login Page +### +LoginPage = () -> + @get = -> browser().navigateTo('/login') - login: () -> - #element('a[href="#/login"]', 'Login button').click() + + @login = -> + #element('a[href="#/login"]', 'Login button').click() #Enter the test credentials input('user.email').enter('admin@email.com') input('user.password').enter('admin1234') element('form button[type="submit"]', 'Click the Login submit button').click() - -RegisterPage = - get: () -> +###* + Register Page +### +RegisterPage = () -> + email = j$.input('email') + username = j$.input('username') + password = j$.input('password') + password2 = j$.input('password2') + agree = j$.input('agree') + + @get = -> browser().navigateTo('/register') - register: () -> - input('user.email').enter('test@email.com') - input('user.username').enter('test') - input('user.password').enter('test') - input('user.password2').enter('test') - element('input[type="checkbox"]').click() - element('form button[type="submit"]', 'Click the submit button').click() + @register = -> + email.enter('test@email.com') + username.enter('test') + password.enter('test') + password2.enter('test') + agree.click() + element('button[type="submit"]', 'Click the submit button').click() + ###* + Karma e2e Tests + ### +App = null +registerPage = null +loginPage = null + describe "Angular-CMS App", -> beforeEach -> - MainPage.index() + browser().navigateTo('/') #Welome Story: the initial page describe 'Index:', -> - it "should display the main index view as default", -> expect(browser().location().path()).toEqual '/' @@ -58,46 +87,55 @@ describe "Angular-CMS App", -> expect(element('.jumbotron').count()).toEqual 1 + ###* +Register - The user registration implementation +### describe 'Register: ', -> beforeEach -> - RegisterPage.get() + browser().navigateTo('/register') it 'should have email and password inputs with a button to submit the form', -> expect(browser().location().path()).toEqual '/register' expect(element('form', 'Login form').count()).toEqual 1 - expect(element('input[type="email"]', 'Email input').count()).toEqual 1 - expect(element('input[type="text"]', 'Username input').count()).toEqual 1 - expect(element('input[type="password"]', 'Password input').count()).toEqual 2 + expect(element('input[name="email"]', 'Email input').count()).toEqual 1 + expect(element('input[name="username"]', 'Username input').count()).toEqual 1 + expect(element('input[name="password"]', 'Password input').count()).toEqual 2 expect(element('button[type="submit"]', 'Submit button').count()).toEqual 1 it 'should allow the user to create a new account', -> - RegisterPage.register() + registerPage = new RegisterPage() + registerPage.register() expect(browser().location().path()).toEqual '/register' sleep 1 expect(browser().location().path()).toEqual '/dashboard' - #The user login implementation + ###* + Login - The user login implementation + ### describe 'Login:', -> #Click the login button each time beforeEach -> + browser().navigateTo('/login') element('a[href="#/login"]', 'Login button').click() #Make sure we end up at the login page to enter our credentials #Make sure there is a username and password input with button - it 'should have email and password inputs with a button to submit the form', -> + it 'should have Username and password inputs with a button to submit the form', -> expect(browser().location().path()).toEqual '/login' - expect(element('#login-form', 'Login form').count()).toEqual 1 - expect(element('input[type="email"]', 'Email input').count()).toEqual 1 - expect(element('input[type="password"]', 'Password input').count()).toEqual 1 + expect(element('form', 'Login form').count()).toEqual 1 + expect(element('input[name="username"]', 'Username input').count()).toEqual 1 + expect(element('input[name="password"]', 'Password input').count()).toEqual 1 expect(element('button[type="submit"]', 'Submit button').count()).toEqual 1 + loginPage = new LoginPage() #Login to the page - LoginPage.login() + loginPage.login() #Wait for the api call to go thru sleep 1 + #We should end up at the dashboard page. expect(browser().location().path()).toEqual '/dashboard' @@ -108,28 +146,25 @@ describe "Angular-CMS App", -> sleep 1 #Profile page - it 'should have a link to the profile page', -> + it 'should have a link to the profile page', -> expect(element('.widget', 'Widget Panel').count()).toEqual 2 expect(element('a[ng-href="#/profile"]', 'the Profile link').count()).toEqual 1 expect(element('.cms-sidebar-nav', 'Sidebar nav').count()).toEqual 1 - - #The user registration implementation - - - #The user forgot password implementation +#The user registration implementation - # The CRUD operations on DB implementation +#The user forgot password implementation - # User table +# The CRUD operations on DB implementation - #User form +# User table +#User form # diff --git a/test/protractor/App.coffee b/test/protractor/App.coffee deleted file mode 100644 index e69de29..0000000 diff --git a/test/protractor/App.js b/test/protractor/App.js deleted file mode 100644 index 70a6b37..0000000 --- a/test/protractor/App.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - App.coffee - - This is the protractor spec that will test the different areas of the application. - */ - -var UsersPage = function () { - - this.newUserBtn = element(by.buttonText('New User')); - this.submitBtn = element(by.buttonText('Submit')); - - this.inputs = { - email: element(protractor.By.model('user.email')), - username: element(protractor.By.model('user.username')), - password: element(protractor.By.model('user.password')), - name: element(protractor.By.model('user.meta.name')), - summary: element(protractor.By.model('user.meta.summary')) - }; - - this.get = function () { - browser.get('http://localhost:9000/#/users'); - }; - - this.setForm = function (email, username, password, name, summary) { - this.newUserBtn.click(); - browser.sleep(500); - this.inputs.username.sendKeys(username); - this.inputs.email.sendKeys(email); - this.inputs.password.sendKeys(password); - this.inputs.name.sendKeys(name); - this.inputs.summary.sendKeys(summary); - - this.submitBtn.click(); - browser.sleep(1000); - }; - -}; - -describe('Angular-CMS', function () { - var usersPage = null; - - describe('Users Page:', function () { - beforeEach(function () { - usersPage = new UsersPage(); - usersPage.get(); - }); - - it('should be able to create a new user', function () { - var username = 'protractor' + Date.now(); - usersPage.setForm(username + '@test.com', username, 'test', 'John Doe', 'This is an example user.'); - }); - }); -}); diff --git a/www/index.ejs b/www/index.ejs index e70df3e..6976f28 100644 --- a/www/index.ejs +++ b/www/index.ejs @@ -1,6 +1,11 @@ <% layout('layout') -%> <% if (!user) { %>

Welcome! Please log in.

+ + Login with Facebook + Login with Google + Login with Twitter +Login <% } else { %>

Hello, <%= user.username %>.

<% } %> diff --git a/www/login.ejs b/www/login.ejs index 22c00ee..0e87566 100644 --- a/www/login.ejs +++ b/www/login.ejs @@ -2,6 +2,19 @@ <% layout('layout') -%>
+
+
+ + +
+
+ + +
+
+ +
+
- diff --git a/app/views/main.html b/app/views/main.html index b44bfe3..625ccae 100755 --- a/app/views/main.html +++ b/app/views/main.html @@ -25,22 +25,23 @@

-
- -
- -

{{item.title}}

-

{{item.body}}

-
-
- +
+ +
+
+ +

{{item.title}}

+

{{item.body}}

+
+
+ +
- diff --git a/karma.conf.js b/karma.conf.js index 2aba216..728057e 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -72,8 +72,7 @@ module.exports = function (config) { coverageReporter: { reporters: [ {type: 'html', dir: 'coverage/'}, - {type: 'lcov', dir: 'coverage/'}, - {type: 'text-summary', dir: 'coverage/'} + {type: 'lcov', dir: 'coverage/', file: 'lcov.info'} ] }, // Continuous Integration mode diff --git a/protractor.conf.js b/protractor.conf.js index d730ecf..0872e12 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -1,7 +1,7 @@ // An example configuration file. exports.config = { - baseUrl: 'http://localhost:9000', + baseUrl: 'http://127.0.0.1:9000', // The address of a running selenium server. seleniumAddress: 'http://localhost:4444/wd/hub', // ---- 3. To use remote browsers via Sauce Labs ----------------------------- @@ -24,7 +24,7 @@ exports.config = { }, params: { - baseUrl: 'http://localhost:9000' + baseUrl: 'http://127.0.0.1:9000' }, // Spec patterns are relative to the current working directly when @@ -40,7 +40,7 @@ exports.config = { defaultTimeoutInterval: 30000 }, onPrepare: function(){ - //browser.driver.get(browser.params.baseUrl); + browser.driver.get(browser.params.baseUrl); var SpecReporter = require('jasmine-spec-reporter'); jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: true})); } diff --git a/test/protractor/app-page.coffee b/test/protractor/app-page.coffee new file mode 100644 index 0000000..caa171e --- /dev/null +++ b/test/protractor/app-page.coffee @@ -0,0 +1,7 @@ + +###* +App Page - I handle general actions in the app. +### +module.exports = AppPage = () -> + @get = -> + browser.get '/' diff --git a/test/protractor/app-spec.coffee b/test/protractor/app-spec.coffee index a0bb6c3..64340fa 100644 --- a/test/protractor/app-spec.coffee +++ b/test/protractor/app-spec.coffee @@ -1,75 +1,7 @@ -###* - J$ Helpers - I am test helpers -### -j$ = - element: (selector, label) -> - console.warn('finding', label) if label - $(selector) - input: (name) -> - $("input[name='#{name}']") - - -###* -App Page - I handle general actions in the app. -### -AppPage = () -> - @get = -> - browser.get '/' - -###* - Login Page - I handle actions on the login page. -### -LoginPage = () -> - @get = -> - browser.get '/#/login' - @login = (u, p) -> - j$.input('username').sendKeys(u) - j$.input('password').sendKeys(p) - j$.element('button[type="submit"]').click() -###* - Register Page - I handle actions on the register page -### -RegisterPage = () -> - email = j$.input('email') - username = j$.input('username') - password = j$.input('password') - password2 = j$.input('password2') - agree = j$.input('agree') - @get = -> - browser.get '/#/register' - @register = -> - email.sendKeys('test@email.com') - username.sendKeys('test') - password.sendKeys('test') - password2.sendKeys('test') - agree.click() - element(protractor.By.css('button[type="submit"]')).click() - -###* -UsersPage - I handle actions on the users page -### -UsersPage = -> - @newUserBtn = element(protractor.By.buttonText("New User")) - @submitBtn = element(protractor.By.buttonText("Submit")) - @inputs = - email: element(protractor.By.model("user.email")) - username: element(protractor.By.model("user.username")) - password: element(protractor.By.model("user.password")) - name: element(protractor.By.model("user.meta.name")) - summary: element(protractor.By.model("user.meta.summary")) - @get = -> - browser.get '/#/users' - - @setForm = (email, username, password, name, summary) -> - @newUserBtn.click() - browser.sleep 500 - @inputs.username.sendKeys username - @inputs.email.sendKeys email - @inputs.password.sendKeys password - @inputs.name.sendKeys name - @inputs.summary.sendKeys summary - @submitBtn.click() - browser.sleep 1000 +AppPage = require('./app-page') +UsersPage = require('./users-page') +LoginPage = require('./login-page') +RegisterPage = require('./register-page') App = null usersPage = null @@ -83,11 +15,10 @@ describe "Angular-CMS App", -> beforeEach -> App = new AppPage() App.get() - #Welome Story: the initial page describe 'Index:', -> it "should display the main index view as default", -> - expect(driver.getCurrentUrl()).toEqual '/' + expect(browser.getCurrentUrl()).toEqual '/' it 'should have a .navbar-brand on the page', -> expect(j$.element('.navbar-brand', 'Site title').count()).toEqual 1 diff --git a/test/protractor/j$.coffee b/test/protractor/j$.coffee new file mode 100644 index 0000000..abd4ed2 --- /dev/null +++ b/test/protractor/j$.coffee @@ -0,0 +1,11 @@ +###* + J$ Helpers - I am test helpers +### +j$ = + element: (selector, label) -> + console.warn('finding', label) if label + $(selector) + input: (name) -> + $('#'+name) + +module.exports = j$ diff --git a/test/protractor/login-page.coffee b/test/protractor/login-page.coffee new file mode 100644 index 0000000..6a5c34e --- /dev/null +++ b/test/protractor/login-page.coffee @@ -0,0 +1,10 @@ +###* + Login Page - I handle actions on the login page. +### +module.exports = LoginPage = () -> + @get = -> + browser.get '/#/login' + @login = (u, p) -> + j$.input('username').sendKeys(u) + j$.input('password').sendKeys(p) + j$.element('button[type="submit"]').click() diff --git a/test/protractor/register-page.coffee b/test/protractor/register-page.coffee new file mode 100644 index 0000000..b6605d0 --- /dev/null +++ b/test/protractor/register-page.coffee @@ -0,0 +1,18 @@ +###* + Register Page - I handle actions on the register page +### +module.exports = RegisterPage = () -> + email = j$.input('email') + username = j$.input('username') + password = j$.input('password') + password2 = j$.input('password2') + agree = j$.input('agree') + @get = -> + browser.get '/#/register' + @register = -> + email.sendKeys('test@email.com') + username.sendKeys('test') + password.sendKeys('test') + password2.sendKeys('test') + agree.click() + element(protractor.By.css('button[type="submit"]')).click() diff --git a/test/protractor/users-page.coffee b/test/protractor/users-page.coffee new file mode 100644 index 0000000..27e3cbd --- /dev/null +++ b/test/protractor/users-page.coffee @@ -0,0 +1,24 @@ +###* +UsersPage - I handle actions on the users page +### +module.exports = UsersPage = ()-> + @newUserBtn = element(protractor.By.buttonText("New User")) + @submitBtn = element(protractor.By.buttonText("Submit")) + @inputs = + email: element(protractor.By.model("user.email")) + username: element(protractor.By.model("user.username")) + password: element(protractor.By.model("user.password")) + name: element(protractor.By.model("user.meta.name")) + summary: element(protractor.By.model("user.meta.summary")) + @get = -> + browser.get '/#/users' + @setForm = (email, username, password, name, summary) -> + @newUserBtn.click() + browser.sleep 500 + @inputs.username.sendKeys username + @inputs.email.sendKeys email + @inputs.password.sendKeys password + @inputs.name.sendKeys name + @inputs.summary.sendKeys summary + @submitBtn.click() + browser.sleep 1000 From a41608e1ccd63106e1a470d9d3d14ddc96fa3702 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sun, 7 Dec 2014 18:26:51 -0800 Subject: [PATCH 17/39] updated travis --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index a686507..808c0ee 100755 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,13 @@ before_script: - 'grunt' #- sleep 2 #- 'grunt serve' +after_script: + - cat coverage/**/lcov.info | codeclimate deploy: provider: heroku api_key: '6ac65b88-dd6d-421f-9fc7-c9ae18f71cb4' on: all_branches: true +addons: + code_climate: + repo_token: 0c38fe0d4c6cc50053304b8cd4859d74624619e2707280ac9287be548e905404 From 77b9ae238af4ef70361fe116c78a60ce95b34928 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sun, 7 Dec 2014 18:43:22 -0800 Subject: [PATCH 18/39] updated package --- gulpfile.js | 8 ++++++++ package.json | 1 + 2 files changed, 9 insertions(+) create mode 100644 gulpfile.js diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..7ae8d03 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,8 @@ +var gulp = require('gulp'); +var ngmin = require('gulp-ngmin'); + +gulp.task('default', function () { + return gulp.src('app/scripts/**/*.coffee') + .pipe(ngmin({dynamic: true})) + .pipe(gulp.dest('./dist')); +}); diff --git a/package.json b/package.json index 56e8912..e3eb2c5 100755 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "grunt-rev": "~0.1.0", "grunt-svgmin": "~0.2.0", "grunt-usemin": "~2.0.2", + "gulp-ngmin": "^0.3.0", "jasmine-core": "^2.1.2", "jasmine-node": "~1.11.0", "jasmine-reporters": "^1.0.1", From 7dbc98e1f3df1e1ac8c4ef005028b4caa938c15c Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sun, 7 Dec 2014 19:32:14 -0800 Subject: [PATCH 19/39] updated rest --- app/scripts/controllers/pages.coffee | 3 +- app/views/pages.html | 58 ++++++++++++++++++++++------ package.json | 2 + routes/rest.js | 49 +++++++++++++++++------ 4 files changed, 89 insertions(+), 23 deletions(-) diff --git a/app/scripts/controllers/pages.coffee b/app/scripts/controllers/pages.coffee index a73e8d2..85b7d00 100644 --- a/app/scripts/controllers/pages.coffee +++ b/app/scripts/controllers/pages.coffee @@ -1,7 +1,7 @@ 'use strict' angular.module('angularCmsApp') - .controller 'PagesCtrl', ($scope, $log, pages, DataService) -> + .controller 'PagesCtrl', ($scope, $log, pages, DataService, cmsNotify) -> $scope.awesomeThings = [ 'HTML5 Boilerplate' 'AngularJS' @@ -28,6 +28,7 @@ angular.module('angularCmsApp') DataService.save('pages', p).then((res) -> $scope.getPages() $scope.page = {} + cmsNotify( '.alerts', 'success', 'Success!', "Page Update.", 5000) $log.info(res) ) diff --git a/app/views/pages.html b/app/views/pages.html index 59c03b4..5e0074b 100755 --- a/app/views/pages.html +++ b/app/views/pages.html @@ -4,17 +4,18 @@
-
+
+
- - +
+ @@ -26,7 +27,16 @@ {{page.publish}} - +
Title DateActions
{{page.created | date:'medium'}} +
+ + +
+
@@ -34,19 +44,45 @@
-
+
Permlink: http://{{App.baseurl}}/?page_id={{page.slug}}
-
-
    -
  • Status: {{page.status}}
  • -
- - +
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
diff --git a/package.json b/package.json index e3eb2c5..45be60f 100755 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "body-parser": "^1.9.3", "body-parser-json": "^1.9.2", "colors": "~0.6.2", + "connect-busboy": "0.0.2", "connect-flash": "^0.1.1", "cookie-parser": "^1.3.3", "easyimage": "~0.1.6", @@ -37,6 +38,7 @@ "express": "~3.4.6", "express-flash": "0.0.2", "express-session": "^1.9.3", + "fs-extra": "^0.12.0", "http-proxy": "^1.3.0", "jps-ds": "~0.0.2", "jquery": "~2.1.0", diff --git a/routes/rest.js b/routes/rest.js index 9b33ce9..d7c9c4a 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -19,7 +19,9 @@ var crypto = require('crypto'); var path = require('path'); var express = require('express'); -var fs = require('fs'), util = require('util'); +var path = require('path'); //used for file path +var fs = require('fs-extra'); //File System - for file manipulatio +var util = require('util'); var request = require('request'); var easyimage = require('easyimage'); var upload = require('jquery-file-upload-middleware'); @@ -28,7 +30,7 @@ var Deferred = require("promised-io/promise").Deferred; var when = require("promised-io/promise"); var bodyParser = require('body-parser'); var markdown = require("markdown").markdown; - +var busboy = require('connect-busboy'); //middleware for form/file upload //Strings for results var MESSAGES = { @@ -242,7 +244,7 @@ var RestResource = { appid = String(req.param('appid')); } - console.log(req.files) + console.log(util.inspect(req, {colors: true})); //Handle if dynamic filenames are enabled var tmp_filename = req.files.file.name || 'tmp_name'; @@ -455,12 +457,17 @@ var cmsRest = function (options) { var app = express(); - console.warn('cmsRest - options', options); + console.log('\n\n---------------------'.verbose); + console.log('cmsRest.js'); console.log('email: admin@email.com '.verbose); console.log('password: admin1234'.verbose) + console.log('---------------------\n\n'.verbose); + + config = options; + //### Express Config //Configure the express app server. //### modules @@ -472,6 +479,10 @@ var cmsRest = function (options) { //v2 mongo rest api app.get(config.apiBase, RestResource.index); app.post(config.apiBase + '/upload', RestResource.upload); + app.get(config.apiBase + '/upload', function(req, res, next){ + res.send({message: 'Upload a file with a POST.'}); + }); + //Always users table app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); @@ -489,18 +500,34 @@ var cmsRest = function (options) { app.set("view options", {layout: false, pretty: true}); app.use(express.static(config.staticDir)); app.use(express.directory(config.publicDir)); - app.use(bodyParser.urlencoded({extended: false})); app.use(bodyParser.json()); + app.use(bodyParser.urlencoded()); app.use("jsonp callback", true); - app.use(config.apiBase + '/upload2', upload.fileHandler()); + app.use(config.apiBase + '/upload2', upload.fileHandler()); app.use(app.router); - app.use(function (req, res, next) { - console.warn(req.param('db'), req.param('collection')) - console.log('%s %s', req.method, req.body, req.url); - next(); - }); }); + + // default options, immediately start reading from the request stream and +// parsing +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 ... + } +}); + + + return app; }; From 370c7ffef28412041e202e291db9adebb287cc41 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Sun, 7 Dec 2014 19:33:19 -0800 Subject: [PATCH 20/39] gulp --- gulpfile.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 gulpfile.js diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..eea6692 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,18 @@ +var coffee, gulp, uglify; + +gulp = require( 'gulp' ); +coffee = require( 'gulp-coffee' ); +uglify = require( 'gulp-uglify' ); + +gulp.task( 'js', function () { + return gulp + .src( './app/scripts/**/*.coffee' ) + .pipe( coffee() ) + .pipe( uglify() ) + .pipe( gulp.dest( './.tmp/scripts' ) ); +} ); + +gulp.task( 'watch', function () { + return gulp + .watch( './app/scripts/**/*.coffee', ['js'] ); +} ); From 3e5614d982bddd230c5a255eddb51b2cd292089f Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Sun, 7 Dec 2014 19:55:02 -0800 Subject: [PATCH 21/39] added form gen --- Gruntfile.js | 133 +++++++++++++----------- app/index.html | 50 ++++++--- app/scripts/app.coffee | 1 + app/scripts/controllers/settings.coffee | 103 +++++++++++++++--- app/styles/main.css | 9 ++ app/views/pages.html | 4 +- app/views/settings.html | 97 ++++++++++++++--- bower.json | 6 +- 8 files changed, 297 insertions(+), 106 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 70ea7cd..986df4e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,27 +22,26 @@ var LIVERELOAD_PORT = 35728; var SERVER_PORT = 9000; //var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}); var mountFolder = function (connect, dir) { - return connect.static(require('path').resolve(dir)); + return connect.static( require( 'path' ).resolve( dir ) ); }; module.exports = function (grunt) { //Connect proxy to route requests to localhost:8181/api - grunt.loadNpmTasks('grunt-connect-proxy'); - require('json-proxy').initialize({}); + grunt.loadNpmTasks( 'grunt-connect-proxy' ); + require( 'json-proxy' ).initialize( {} ); // Load grunt tasks automatically - require('load-grunt-tasks')(grunt); + require( 'load-grunt-tasks' )( grunt ); // Time how long tasks take. Can help when optimizing build times - require('time-grunt')(grunt); + require( 'time-grunt' )( grunt ); - // Define the configuration for all the tasks - grunt.initConfig({ + var GruntConfig = { // Project settings yeoman: { // configurable paths - app: require('./bower.json').appPath || 'app', + app: require( './bower.json' ).appPath || 'app', dist: 'dist', tmp: '.tmp' }, @@ -54,11 +53,11 @@ module.exports = function (grunt) { tasks: ['newer:coffee:dist'] }, coffeeTest: { - files: ['test/spec/{,**/}*.{coffee,litcoffee,coffee.md}'], + files: ['test/spec/{,**/}*.{coffee,litcoffee,coffee.md}'], tasks: ['coffee:test', 'newer:coffee:test', 'karma:unit'] }, coffeeProtractorTest: { - files: ['test/protractor/{,**/}*.{coffee,litcoffee,coffee.md}'], + files: ['test/protractor/{,**/}*.{coffee,litcoffee,coffee.md}'], tasks: ['coffee:test', 'newer:coffee:test', 'protractor'] }, compass: { @@ -93,9 +92,10 @@ module.exports = function (grunt) { hostname: '127.0.0.1', livereload: 35729, middleware: function (connect, options) { - return [require('json-proxy').initialize(proxyConfig), - mountFolder(connect, '.grunt'), - mountFolder(connect, '.tmp') + return [ + require( 'json-proxy' ).initialize( proxyConfig ), + mountFolder( connect, '.grunt' ), + mountFolder( connect, '.tmp' ) ]; } }, @@ -104,9 +104,10 @@ module.exports = function (grunt) { open: true, base: ['.tmp', '<%= yeoman.app %>'], middleware: function (connect, options) { - return [require('json-proxy').initialize(proxyConfig), - mountFolder(connect, '.tmp'), - mountFolder(connect, 'app') + return [ + require( 'json-proxy' ).initialize( proxyConfig ), + mountFolder( connect, '.tmp' ), + mountFolder( connect, 'app' ) ]; } } @@ -122,8 +123,9 @@ module.exports = function (grunt) { livereload: false, base: '<%= yeoman.dist %>', middleware: function (connect, options) { - return [require('json-proxy').initialize(proxyConfig), - mountFolder(connect, 'dist') + return [ + require( 'json-proxy' ).initialize( proxyConfig ), + mountFolder( connect, 'dist' ) ]; } } @@ -134,9 +136,9 @@ module.exports = function (grunt) { open: true, middleware: function (connect, options) { return [ - mountFolder(connect, '.grunt'), - mountFolder(connect, '.tmp'), - mountFolder(connect, 'docs') + mountFolder( connect, '.grunt' ), + mountFolder( connect, '.tmp' ), + mountFolder( connect, 'docs' ) ]; } } @@ -147,7 +149,7 @@ module.exports = function (grunt) { jshint: { options: { jshintrc: '.jshintrc', - reporter: require('jshint-stylish') + reporter: require( 'jshint-stylish' ) }, all: [ //'Gruntfile.js' @@ -269,9 +271,11 @@ module.exports = function (grunt) { rev: { dist: { files: { - src: ['<%= yeoman.dist %>/scripts/{,*/}*.js', '<%= yeoman.dist %>/styles/{,*/}*.css', + src: [ + '<%= yeoman.dist %>/scripts/{,*/}*.js', '<%= yeoman.dist %>/styles/{,*/}*.css', //'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', - '<%= yeoman.dist %>/styles/fonts/*'] + '<%= yeoman.dist %>/styles/fonts/*' + ] } } }, @@ -340,7 +344,7 @@ module.exports = function (grunt) { removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true - */ + */ }, files: [ @@ -406,11 +410,13 @@ module.exports = function (grunt) { dot: true, cwd: '<%= yeoman.app %>', dest: '<%= yeoman.dist %>', - src: ['*.{ico,png,txt}', '.htaccess', + src: [ + '*.{ico,png,txt}', '.htaccess', //'bower_components/**/*', 'scripts/libs/*', 'images/{,*/}*.{webp}', - 'fonts/*'] + 'fonts/*' + ] }, { expand: true, @@ -430,17 +436,22 @@ module.exports = function (grunt) { // Run some tasks in parallel to speed up the build process concurrent: { - server: ['coffee:dist', + server: [ + 'coffee:dist', // 'compass:server', - 'ngtemplates', 'copy:styles'], - test: ['coffee', + 'ngtemplates', 'copy:styles' + ], + test: [ + 'coffee', // 'compass', - 'copy:styles'], + 'copy:styles' + ], dist: [ 'coffee', // 'compass:dist', 'ngtemplates', - 'copy:styles', 'svgmin', 'htmlmin'] + 'copy:styles', 'svgmin', 'htmlmin' + ] }, // By default, your `index.html`'s will take care of @@ -534,7 +545,7 @@ module.exports = function (grunt) { module: 'angularCmsApp', //url: 'views', url: function (url) { - return url.replace('app/', ''); + return url.replace( 'app/', '' ); }, prefix: '', htmlmin: { @@ -569,8 +580,7 @@ module.exports = function (grunt) { options: { keepAlive: true, // If false, the grunt process stops when the test fails. noColor: false, // If true, protractor will not use colors in its output. - args: { - } + args: {} }, test: { options: { @@ -580,7 +590,6 @@ module.exports = function (grunt) { } }, - //Coveralls code coverage coveralls: { options: { @@ -605,39 +614,45 @@ module.exports = function (grunt) { ] } } - }); + }; + + // Define the configuration for all the tasks + grunt.initConfig( GruntConfig ); - grunt.registerTask('serve', function (target) { + grunt.registerTask( 'serve', function (target) { if (target === 'dist') { - return grunt.task.run(['build', 'connect:dist:keepalive']); + return grunt.task.run( ['build', 'connect:dist:keepalive'] ); } - grunt.task.run(['clean:server', 'concurrent:server', 'autoprefixer', 'connect:livereload', 'watch']); - }); + grunt.task.run( ['clean:server', 'concurrent:server', 'autoprefixer', 'connect:livereload', 'watch'] ); + } ); - grunt.registerTask('server', function () { - grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); - grunt.task.run(['serve']); - }); + grunt.registerTask( 'server', function () { + grunt.log.warn( 'The `server` task has been deprecated. Use `grunt serve` to start a server.' ); + grunt.task.run( ['serve'] ); + } ); - grunt.registerTask('test', function (target) { - grunt.task.run(['clean:server', 'concurrent:test', 'autoprefixer', 'connect:test']); + grunt.registerTask( 'test', function (target) { + grunt.task.run( ['clean:server', 'concurrent:test', 'autoprefixer', 'connect:test'] ); if (target === 'e2e') { - return grunt.task.run(['karma', 'protractor_webdriver', 'protractor', 'coveralls']); - } else if(target === 'server'){ - return grunt.task.run(['coffee:test', 'mochaTest']); + return grunt.task.run( ['karma', 'protractor_webdriver', 'protractor', 'coveralls'] ); + } else if (target === 'server') { + return grunt.task.run( ['coffee:test', 'mochaTest'] ); } else { - return grunt.task.run(['karma:unit', 'coveralls']); + return grunt.task.run( ['karma:unit', 'coveralls'] ); } - }); + } ); -grunt.registerTask('ptor', ['coffee:test', 'protractor_webdriver', 'protractor']); - grunt.registerTask('build-docs', [ 'useminPrepare', 'autoprefixer', 'concat', 'ngmin']); - grunt.registerTask('build', ['clean:dist', 'useminPrepare', 'concurrent:dist', 'autoprefixer', 'concat', 'ngmin', 'copy:dist', /*'cdnify',*/ 'cssmin', 'uglify', 'rev', 'usemin']); + grunt.registerTask( 'ptor', ['coffee:test', 'protractor_webdriver', 'protractor'] ); + grunt.registerTask( 'build-docs', ['useminPrepare', 'autoprefixer', 'concat', 'ngmin'] ); + grunt.registerTask( 'build', [ + 'clean:dist', 'useminPrepare', 'concurrent:dist', 'autoprefixer', 'concat', 'ngmin', 'copy:dist', /*'cdnify',*/ + 'cssmin', 'uglify', 'rev', 'usemin' + ] ); - grunt.registerTask('docs', ['coffee', 'ngdocs', 'connect:docs', 'watch:ngdocs']); - grunt.registerTask('default', ['newer:jshint', 'test', 'build']); + grunt.registerTask( 'docs', ['coffee', 'ngdocs', 'connect:docs', 'watch:ngdocs'] ); + grunt.registerTask( 'default', ['newer:jshint', 'test', 'build'] ); - grunt.registerTask('heroku:production', 'build'); - grunt.registerTask('heroku:development', 'build'); + grunt.registerTask( 'heroku:production', 'build' ); + grunt.registerTask( 'heroku:development', 'build' ); }; diff --git a/app/index.html b/app/index.html index 4c38951..3b6b00b 100755 --- a/app/index.html +++ b/app/index.html @@ -93,16 +93,42 @@ - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -111,16 +137,6 @@ - - - - - - - - - - diff --git a/app/scripts/app.coffee b/app/scripts/app.coffee index 72ee9ab..a3506f1 100644 --- a/app/scripts/app.coffee +++ b/app/scripts/app.coffee @@ -26,6 +26,7 @@ app = angular.module('angularCmsApp', [ 'ngRoute' 'ngAnimate' 'mgcrea.ngStrap' + 'fg' #'cms.Templates' ]) .config ($routeProvider) -> diff --git a/app/scripts/controllers/settings.coffee b/app/scripts/controllers/settings.coffee index bdc3b92..41d3415 100644 --- a/app/scripts/controllers/settings.coffee +++ b/app/scripts/controllers/settings.coffee @@ -1,17 +1,92 @@ 'use strict' angular.module('angularCmsApp') - .controller 'SettingsCtrl', ($scope) -> - $scope.awesomeThings = [ - 'HTML5 Boilerplate' - 'AngularJS' - 'Karma' - ] - $scope.config = Config - $scope.tabs = [ - title: 'General' - content: '' - , - title: 'Client' - content: '' - ] +.controller 'SettingsCtrl', ($scope, mySchema) -> + $scope.awesomeThings = [ + 'HTML5 Boilerplate' + 'AngularJS' + 'Karma' + ] + $scope.myForm = + schema: mySchema + + $scope.config = Config + $scope.tabs = [ + title: 'General' + content: '' + , + title: 'Client' + content: '' + ] + +angular.module('angularCmsApp').value "mySchema", + fields: [ + { + type: "text" + name: "firstName" + displayName: "First name" + validation: + messages: {} + required: true + + placeholder: "Enter your first name here" + tooltip: "Enter your first name here" + } + { + type: "text" + name: "lastName" + displayName: "Last name" + validation: + messages: {} + required: true + + placeholder: "Enter your last name here" + tooltip: "Enter your last name here" + } + { + type: "radiobuttonlist" + name: "sex" + displayName: "Sex" + options: [ + { + value: "male" + text: "Male" + } + { + value: "female" + text: "Female" + } + ] + value: "male" + } + { + type: "email" + name: "email" + displayName: "Email" + validation: + messages: {} + + placeholder: "Enter your email address here" + tooltip: "Enter your email address here" + } + { + type: "checkboxlist" + name: "color" + displayName: "Colors" + options: [ + { + value: "red" + text: "Red" + } + { + value: "blue" + text: "Blue" + } + { + value: "green" + text: "Green" + } + ] + value: {} + } + ] diff --git a/app/styles/main.css b/app/styles/main.css index 6975aca..1f29dee 100755 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -2,10 +2,19 @@ http://127.0.0.1:9000/styles/main.css http://localhost:9000/styles/main.css */ +@import url('https://cdn.rawgit.com/McNull/angular-form-gen/v0.0.1/dist/angular-form-gen.min.css'); + .navbar-avatar { height: 20px; } +html { + overflow-y: scroll; +} + +.needs-some-more-space { + margin-top: 20px; +} .actions { width: 100px; text-align: center; diff --git a/app/views/pages.html b/app/views/pages.html index 5e0074b..03aa225 100755 --- a/app/views/pages.html +++ b/app/views/pages.html @@ -29,10 +29,10 @@ {{page.created | date:'medium'}}
- -
diff --git a/app/views/settings.html b/app/views/settings.html index bd09b72..f0788d7 100755 --- a/app/views/settings.html +++ b/app/views/settings.html @@ -1,9 +1,85 @@
-
+
+ + + +
+ +
+ +
+
+ +
+ +
+
+
+ +
+
+
+ +
+ + +
+ +
+ + +
+
Example Form
+
+
+ + + +
+
+ + + +
+ +
+ +
+ + + + + + + + +
- + General @@ -11,16 +87,15 @@ - + Network - - + + - - - + +
-
- -
+
diff --git a/bower.json b/bower.json index 69c79c3..1a23f3e 100755 --- a/bower.json +++ b/bower.json @@ -19,9 +19,13 @@ "angular-resource": "~1.2.21", "angular-cookies": "~1.2.21", "angular-animate": "~1.2.21", - "angular-sanitize": "~1.2.21" + "angular-sanitize": "~1.2.21", + "angular-form-gen": "~0.0.2" }, "devDependencies": { "angular-mocks": "~1.2.21" + }, + "resolutions": { + "bootstrap": "~3.2.0" } } From dce738bd1484d39aa523760246dd4eb61969c88f Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Sun, 7 Dec 2014 20:05:20 -0800 Subject: [PATCH 22/39] websockets --- app/scripts/controllers/admin.coffee | 89 ++++++- app/views/admin.html | 24 ++ routes/rest.js | 336 +++++++++++++-------------- routes/socketserver.js | 1 + server.js | 4 +- 5 files changed, 269 insertions(+), 185 deletions(-) diff --git a/app/scripts/controllers/admin.coffee b/app/scripts/controllers/admin.coffee index 435f8ab..69d58c5 100644 --- a/app/scripts/controllers/admin.coffee +++ b/app/scripts/controllers/admin.coffee @@ -1,9 +1,86 @@ 'use strict' angular.module('angularCmsApp') - .controller 'AdminCtrl', ($scope) -> - $scope.awesomeThings = [ - 'HTML5 Boilerplate' - 'AngularJS' - 'Karma' - ] +.controller 'AdminCtrl', ($scope) -> + $scope.awesomeThings = [ + 'HTML5 Boilerplate' + 'AngularJS' + 'Karma' + ] + log = (args) -> + s += "[" + Date.now() + "] " + args.toString() + "\n" + $("textarea").val s + + notify = (type, msg) -> + html = "
" + msg + "
" + $(".messages").empty() + $(".messages").append html + return + WebSocketClient = (options) -> + _ws = undefined + _ws = new WebSocket(options.endpoint, options.protocol) + _ws.onmessage = (e) -> + notify "info", e.data + console.log e.data + return + + _ws.onerror = (e) -> + notify "danger", "There was an error" + console.log e + return + + _ws.onclose = (e) -> + notify "danger", "Socket is now closed" + console.log e + return + + _ws.onopen = (e) -> + notify "success", "Socket is now open" + _ws.send "update" + return + + instance: _ws + close: -> + _ws.close() + + send: (obj) -> + try + _ws.send obj + catch err + throw err + return + + s = "" + + #Document + $(document).ready -> + ws = null + + #Open + $(".btn-connect").click (e) -> + options = + endpoint: $("#ws-endpoint").val() + protocol: $("#ws-protocol").val() + + ws = new WebSocketClient(options) + console.log ws + log "Connecting to socket" + return + + + #Close + $(".btn-disconnect").click (e) -> + ws.close() + log "Disconnecting from socket" + return + + + #Send + $(".btn-message").click (e) -> + msg = $("#ws-msg").val() + log "Sending: " + msg + ws.send msg + return + + return + diff --git a/app/views/admin.html b/app/views/admin.html index e69de29..5937b49 100755 --- a/app/views/admin.html +++ b/app/views/admin.html @@ -0,0 +1,24 @@ +
+

WebSockets

+

Use this document as a way to quickly start a new WebSocket project.

+
+
+ + +
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+Log + \ No newline at end of file diff --git a/routes/rest.js b/routes/rest.js index d7c9c4a..37405e4 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -16,21 +16,21 @@ */ //## Required Modules -var crypto = require('crypto'); -var path = require('path'); -var express = require('express'); -var path = require('path'); //used for file path -var fs = require('fs-extra'); //File System - for file manipulatio -var util = require('util'); -var request = require('request'); -var easyimage = require('easyimage'); -var upload = require('jquery-file-upload-middleware'); -var sio = require('socket.io'); -var Deferred = require("promised-io/promise").Deferred; -var when = require("promised-io/promise"); -var bodyParser = require('body-parser'); -var markdown = require("markdown").markdown; -var busboy = require('connect-busboy'); //middleware for form/file upload +var crypto = require( 'crypto' ); +var path = require( 'path' ); +var express = require( 'express' ); +var path = require( 'path' ); //used for file path +var fs = require( 'fs-extra' ); //File System - for file manipulatio +var util = require( 'util' ); +var request = require( 'request' ); +var easyimage = require( 'easyimage' ); +var upload = require( 'jquery-file-upload-middleware' ); +var sio = require( 'socket.io' ); +var Deferred = require( "promised-io/promise" ).Deferred; +var when = require( "promised-io/promise" ); +var bodyParser = require( 'body-parser' ); +var markdown = require( "markdown" ).markdown; +var busboy = require( 'connect-busboy' ); //middleware for form/file upload //Strings for results var MESSAGES = { @@ -39,8 +39,8 @@ var MESSAGES = { USER_REGISTRATION_EXISTS: 'User already in exists.' }; -var DS = require('jps-ds').DS; -var _ds = new DS({ +var DS = require( 'jps-ds' ).DS; +var _ds = new DS( { host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', models: { 'groups': { @@ -117,16 +117,16 @@ var _ds = new DS({ active: Boolean } } -}); +} ); function delay(ms, value) { // create a new Deferred var deferred = new Deferred(); - setTimeout(function () { + setTimeout( function () { // fulfill the deferred/promise, all listeners to the promise will be notified, and // provided the value as the value of the promise - deferred.resolve(value); - }, ms); + deferred.resolve( value ); + }, ms ); // return the promise that is associated with the Deferred object return deferred.promise; } @@ -134,18 +134,17 @@ function delay(ms, value) { //### hashPassword //Hash password using basic sha1 hash. var hashPassword = function (pass, salt) { - var shasum = crypto.createHash('sha1'); - shasum.update(salt + pass); + var shasum = crypto.createHash( 'sha1' ); + shasum.update( salt + pass ); - return shasum.digest('hex'); + return shasum.digest( 'hex' ); } //## Configuration - //### Colors Config -var colors = require('colors'); -colors.setTheme({ +var colors = require( 'colors' ); +colors.setTheme( { silly: 'rainbow', input: 'grey', verbose: 'cyan', @@ -156,11 +155,10 @@ colors.setTheme({ warn: 'yellow', debug: 'blue', error: 'red' -}); +} ); //# Class Objects - //## Rest Resource //I am a RESTful resource object for handling CRUD operations on v1 or v2 api. var RestResource = { @@ -174,16 +172,16 @@ var RestResource = { v1: 'https://www..com', v2: '/api/v2/' }, - log: function(){ - console.log(util.inspect(arguments, {colors: true})); + log: function () { + console.log( util.inspect( arguments, {colors: true} ) ); }, //### index //I handle displaying a message with the version for this api. index: function (req, res, next) { - res.json({ + res.json( { message: 'REST API Server ' + RestResource.useversion - }); + } ); }, /** * //### login @@ -194,7 +192,7 @@ var RestResource = { */ login: function (req, res, next) { var query = {}; - console.log(req.body); + console.log( req.body ); //TODO: Need to make this externalized. if (req.body.username) { @@ -205,16 +203,15 @@ var RestResource = { } //TODO: Hashing on client side - query.password = hashPassword(req.body.password, req.body.email); + query.password = hashPassword( req.body.password, req.body.email ); - console.log('Login Query: ', query); + console.log( 'Login Query: ', query ); - _ds.findOne('users', query).then(function (data) { - res.json(200, data); + _ds.findOne( 'users', query ).then( function (data) { + res.json( 200, data ); }, function (err) { - res.json(400, err); - }); - + res.json( 400, err ); + } ); }, /** @@ -229,8 +226,8 @@ var RestResource = { query = { email: req.body.email }; - data.password = hashPassword(req.body.password, req.body.email), - console.log(String("Register user").debug, req.body); + data.password = hashPassword( req.body.password, req.body.email ), + console.log( String( "Register user" ).debug, req.body ); }, session: function (req, res, next) { }, @@ -240,11 +237,11 @@ var RestResource = { upload: function (req, res, next) { var appid = 'public'; - if (req.param('appid')) { - appid = String(req.param('appid')); + if (req.param( 'appid' )) { + appid = String( req.param( 'appid' ) ); } - console.log(util.inspect(req, {colors: true})); + console.log( util.inspect( req, {colors: true} ) ); //Handle if dynamic filenames are enabled var tmp_filename = req.files.file.name || 'tmp_name'; @@ -263,30 +260,30 @@ var RestResource = { } //Log the vars - console.log(x1, x2, y1, y2, height, width, thumb_path); + console.log( x1, x2, y1, y2, height, width, thumb_path ); //Orignal image - console.log(String('Temp Path: ' + tmp_path).warn); - console.log(String('Target Dir: ' + target_dir).warn); - console.log(String('Target Path: ' + target_path).warn); + console.log( String( 'Temp Path: ' + tmp_path ).warn ); + console.log( String( 'Target Dir: ' + target_dir ).warn ); + console.log( String( 'Target Path: ' + target_path ).warn ); //Thumbnail image - console.log(String('Original File: ' + filename).debug); - console.log(String('Original File Path: ' + target_path).debug); - console.log(String('Thumb Dir: ' + thumb_dir).debug); - console.log(String('Thumb Path: ' + thumb_path).debug); + console.log( String( 'Original File: ' + filename ).debug ); + console.log( String( 'Original File Path: ' + target_path ).debug ); + console.log( String( 'Thumb Dir: ' + thumb_dir ).debug ); + console.log( String( 'Thumb Path: ' + thumb_path ).debug ); //Create the directory and move the file to that directory - fs.mkdir(target_dir, 0777, function (e) { + fs.mkdir( target_dir, 0777, function (e) { //Rename the file - fs.rename(tmp_path, target_path, function (err) { + fs.rename( tmp_path, target_path, function (err) { if (err) { - console.error('File Rename Error:', err); + console.error( 'File Rename Error:', err ); } //Create the thumb directory - fs.mkdir(thumb_dir, 0777, function (e) { + fs.mkdir( thumb_dir, 0777, function (e) { //Create the thumbnail from the default image var imgOptions = { @@ -300,8 +297,8 @@ var RestResource = { }; //Resize the image - easyimg.resize(imgOptions, function (e) { - console.log('easyimg', imgOptions, e); + easyimg.resize( imgOptions, function (e) { + console.log( 'easyimg', imgOptions, e ); req.files.file.target_dir = target_dir; req.files.file.target_path = target_path; req.files.file.thumb_path = thumb_path; @@ -322,52 +319,52 @@ var RestResource = { }; //Output the results - res.send(json); - }); - }); - }); - }); + res.send( json ); + } ); + } ); + } ); + } ); }, //### get //I handle gathering records dynamically from a call to the v2 api. get: function (req, res, next) { - if (req.param('id')) { - console.log('find one', req.params.id); - _ds.findOne(req.params.collection, req.params.id).then(function (data) { - res.send(data); + if (req.param( 'id' )) { + console.log( 'find one', req.params.id ); + _ds.findOne( req.params.collection, req.params.id ).then( function (data) { + res.send( data ); }, function (err) { - res.send(err); - }); + res.send( err ); + } ); } else { - _ds.findAll(req.params.collection).then(function (data) { - res.send(data); + _ds.findAll( req.params.collection ).then( function (data) { + res.send( data ); }, function (err) { - res.send(err); - }); + res.send( err ); + } ); } }, //### add //I handle adding a record to the database. add: function (req, res, next) { - _ds.create(req.params.collection, req.body).then(function (data) { - console.warn('create', data); - res.send(data); + _ds.create( req.params.collection, req.body ).then( function (data) { + console.warn( 'create', data ); + res.send( data ); }, function (err) { - res.send(err); - }); + res.send( err ); + } ); }, //### edit //I handle edit: function (req, res, next) { var data = req.body; delete data._id; - _ds.update(req.params.collection, req.params.id, data).then(function (data) { - console.warn(data); - res.send(data); + _ds.update( req.params.collection, req.params.id, data ).then( function (data) { + console.warn( data ); + res.send( data ); }, function (err) { - res.send(err); - }); + res.send( err ); + } ); }, //### view //I handle @@ -376,77 +373,71 @@ var RestResource = { //### destroy //I handle destroy: function (req, res, next) { - _ds.destroy(req.params.collection, req.params.id).then(function (data) { - console.warn(data); - res.send(data); + _ds.destroy( req.params.collection, req.params.id ).then( function (data) { + console.warn( data ); + res.send( data ); }, function (err) { - res.send(err); - }); + res.send( err ); + } ); }, readme: function (res, req) { var localPath = __dirname + '/../README.md'; - fs.readFile(localPath, 'utf8', function (err, data) { + fs.readFile( localPath, 'utf8', function (err, data) { if (err) { - req.end('There was an error.'); - return console.log(err); + req.end( 'There was an error.' ); + return console.log( err ); } else { - req.writeHead(200, { + req.writeHead( 200, { "Content-Type": 'utf8', "Content-Length": data.length - }); - req.end(data); + } ); + req.end( data ); } - console.log(data); - }); + console.log( data ); + } ); }, plugins: function (req, res) { - var result = fs.readdir('./app/cms-plugins', function (err, files) { - console.log(files); - res.header('Content-Type', 'application/json'); - res.jsonp(200, files); - }); + var result = fs.readdir( './app/cms-plugins', function (err, files) { + console.log( files ); + res.header( 'Content-Type', 'application/json' ); + res.jsonp( 200, files ); + } ); } }; - - - - //### getFile //Get file contents from a file. function getFile(localPath, mimeType, res) { - fs.readFile(localPath, 'utf8', function (err, data) { + fs.readFile( localPath, 'utf8', function (err, data) { if (err) { - res.end('There was an error.'); - return console.log(err); + res.end( 'There was an error.' ); + return console.log( err ); } else { - res.writeHead(200, { + res.writeHead( 200, { "Content-Type": 'utf8', "Content-Length": data.length - }); - res.end(data); + } ); + res.end( data ); } - console.log(data); + console.log( data ); - }); + } ); }; //### writeFile //Write contents to a file function writeFile(localPath, contents) { // create a stream, and create the file if it doesn't exist - stream = fs.createWriteStream(localPath); - console.log('writeFile', localPath); - stream.on("open", function () { + stream = fs.createWriteStream( localPath ); + console.log( 'writeFile', localPath ); + stream.on( "open", function () { // write to and close the stream at the same time - stream.end(contents, 'utf-8'); - res.end(html); - }); + stream.end( contents, 'utf-8' ); + res.end( html ); + } ); }; - - var config = {}; var publicPath = config.publicDir; var uploadsTmpDir = config.uploadsTmpDir; @@ -457,74 +448,65 @@ var cmsRest = function (options) { var app = express(); - console.log('\n\n---------------------'.verbose); - console.log('cmsRest.js'); - console.log('email: admin@email.com '.verbose); - console.log('password: admin1234'.verbose) - console.log('---------------------\n\n'.verbose); - + console.log( '\n\n---------------------'.verbose ); + console.log( 'cmsRest.js' ); + console.log( 'email: admin@email.com '.verbose ); + console.log( 'password: admin1234'.verbose ) + console.log( '---------------------\n\n'.verbose ); config = options; - - //### Express Config //Configure the express app server. //### modules //Gather all of the files and folders in the app/modules directory - app.get(config.apiBase + '/plugins', RestResource.plugins); + app.get( config.apiBase + '/plugins', RestResource.plugins ); //# Routes //### v2 API - app.get(config.apiBase + '/readme', RestResource.readme); + app.get( config.apiBase + '/readme', RestResource.readme ); //v2 mongo rest api - app.get(config.apiBase, RestResource.index); - app.post(config.apiBase + '/upload', RestResource.upload); - app.get(config.apiBase + '/upload', function(req, res, next){ - res.send({message: 'Upload a file with a POST.'}); - }); - + app.get( config.apiBase, RestResource.index ); + app.post( config.apiBase + '/upload', RestResource.upload ); + app.get( config.apiBase + '/upload', function (req, res, next) { + res.send( {message: 'Upload a file with a POST.'} ); + } ); //Always users table - app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); - app.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); - app.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); + app.post( config.apiBase + '/users/login', bodyParser.json(), RestResource.login ); + app.post( config.apiBase + '/users/register', bodyParser.json(), RestResource.register ); + app.post( config.apiBase + '/users/session', bodyParser.json(), RestResource.session ); //Dynamic REST - app.get(config.apiBase + '/:db/:collection/:id?', RestResource.get); - app.post(config.apiBase + '/:db/:collection', bodyParser.json(), RestResource.add); - app.put(config.apiBase + '/:db/:collection/:id', bodyParser.json(), RestResource.edit); - app.delete(config.apiBase + '/:db/:collection/:id', RestResource.destroy); - - - app.configure(function () { - app.set("view options", {layout: false, pretty: true}); - app.use(express.static(config.staticDir)); - app.use(express.directory(config.publicDir)); - app.use(bodyParser.json()); - app.use(bodyParser.urlencoded()); - app.use("jsonp callback", true); - - app.use(config.apiBase + '/upload2', upload.fileHandler()); - app.use(app.router); - }); - - // default options, immediately start reading from the request stream and -// parsing -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 ... - } -}); + app.get( config.apiBase + '/:db/:collection/:id?', RestResource.get ); + app.post( config.apiBase + '/:db/:collection', bodyParser.json(), RestResource.add ); + app.put( config.apiBase + '/:db/:collection/:id', bodyParser.json(), RestResource.edit ); + app.delete( config.apiBase + '/:db/:collection/:id', RestResource.destroy ); + + app.configure( function () { + 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 ... + } + } ); + app.set( "view options", {layout: false, pretty: true} ); + app.use( express.static( config.staticDir ) ); + app.use( express.directory( config.publicDir ) ); + app.use( bodyParser.json() ); + app.use( bodyParser.urlencoded() ); + app.use( "jsonp callback", true ); + + app.use( config.apiBase + '/upload2', upload.fileHandler() ); + app.use( app.router ); + } ); diff --git a/routes/socketserver.js b/routes/socketserver.js index 188ae37..c3207de 100644 --- a/routes/socketserver.js +++ b/routes/socketserver.js @@ -80,6 +80,7 @@ var SocketServer = { //Handle when a client is connected. io.sockets.on( 'connection', function (socket) { + console.warn('connection', socket); //push to connections array self.connections.push( socket ); diff --git a/server.js b/server.js index cfb3314..2dbc51d 100755 --- a/server.js +++ b/server.js @@ -61,7 +61,7 @@ var cmsRest = require('./routes/rest'); var rest = new cmsRest(config); var auth = new cmsAuth(config, rest); -auth.listen(config.port || process.env.PORT, function () { +var webapp = auth.listen(config.port || process.env.PORT, function () { console.log(String('Node.js REST server listening on port: ' + config.port).verbose); }); @@ -70,7 +70,7 @@ auth.listen(config.port || process.env.PORT, function () { var socket = require('./routes/socketserver').SocketServer; //Initialize socket server and rest server -socket.init(auth); +socket.init(webapp); From 2a50fdab3e59735c5b58b8f9458666e3400146d6 Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Sun, 7 Dec 2014 20:21:15 -0800 Subject: [PATCH 23/39] Sockets updated --- Gruntfile.js | 1 + app/index.html | 2 +- app/scripts/controllers/admin.coffee | 97 ++++++++++++++++++++++++++++ app/views/admin.html | 62 +++++++++++++++++- routes/socketserver.js | 70 +++++++++++++++++++- 5 files changed, 228 insertions(+), 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 986df4e..33a50d8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,6 +12,7 @@ var serverEndpoint = 'http://localhost:8181'; var proxyConfig = { proxy: { forward: { + '/socket.io/*': serverEndpoint, '/socket.io': serverEndpoint, '/api': serverEndpoint } diff --git a/app/index.html b/app/index.html index 3b6b00b..a9d41e4 100755 --- a/app/index.html +++ b/app/index.html @@ -91,7 +91,7 @@ ga('send', 'pageview'); - + diff --git a/app/scripts/controllers/admin.coffee b/app/scripts/controllers/admin.coffee index 69d58c5..f886170 100644 --- a/app/scripts/controllers/admin.coffee +++ b/app/scripts/controllers/admin.coffee @@ -7,6 +7,102 @@ angular.module('angularCmsApp') 'AngularJS' 'Karma' ] + window.socket = io.connect("http://localhost:8181") + socket.on "message", (data) -> + log.push data + $("#output").val JSON.stringify(log) + console.log data + return + + $scope.App = + logs: [] + messages: [] + socket: null + defaults: + socketServer: "" + debug: false + input: "" + output: "" + + + ###* + Handle initializing socket.io + ### + init: (options) -> + self = this + @options = $.extend(@defaults, options) + @socket = io.connect(@options.socketServer) + @socket.on "connect", -> + console.log "Connected to socket.io" + return + + @socket.on "msg", (data) -> + self.onMessage data + return + + console.log "App.init", options + return + + + ###* + Handle the response from the server. + ### + onMessage: (data) -> + self = this + self.log data + self.addMessage data + console.log "socket.io -> sent", data + return + + + ###* + Handle sending a message to socket.io server. + @param data + ### + send: (data) -> + self = this + self.input = "" + console.log "sent -> socket.io ", data + self.socket.emit "msgEvent", data, (response) -> + response.from = "server" + self.onMessage response + return + + return + + + ###* + Handle logging the messages. + @param what + ### + log: (what) -> + self = this + $scope.$apply -> + self.logs.push what + return + + return + + addMessage: (what) -> + self = this + $scope.$apply -> + self.messages.push what + return + + return + + clear: -> + self = this + self.messages = [] + self.logs = [] + return + + $scope.App.init + socketServer: "/" + input: "#input" + output: "#output" + + log = (args) -> s += "[" + Date.now() + "] " + args.toString() + "\n" $("textarea").val s @@ -16,6 +112,7 @@ angular.module('angularCmsApp') $(".messages").empty() $(".messages").append html return + WebSocketClient = (options) -> _ws = undefined _ws = new WebSocket(options.endpoint, options.protocol) diff --git a/app/views/admin.html b/app/views/admin.html index 5937b49..95095a4 100755 --- a/app/views/admin.html +++ b/app/views/admin.html @@ -1,3 +1,4 @@ +

WebSockets

Use this document as a way to quickly start a new WebSocket project.

@@ -21,4 +22,63 @@

WebSockets


Log - \ No newline at end of file + + +
+ + +
+ + Send +
+
+ + +
+
+ Output +
+
+
+ + + + + + + + + + + + + + + + +
ClientMessageTime
{{item.id}}{{item.message}}{{item.datetime | date:'mediumTime'}}
+
+
+ +
+ +
diff --git a/routes/socketserver.js b/routes/socketserver.js index c3207de..1294916 100644 --- a/routes/socketserver.js +++ b/routes/socketserver.js @@ -18,7 +18,16 @@ //Start the websocket server //SocketServer.init(proxyServer); -var sio = require( 'socket.io' ); +var sio = require( 'socket.io' ), q = require( 'q' ); + +var delay = function (fn, time) { + var defer = q.defer(); + setTimeout( function () { + defer.resolve( fn() ); + }, time ); + return defer.promise; +} + //Hold the ncmss of events that this socket server listens for and emits var CmsSocket = { events: { @@ -40,6 +49,7 @@ var CmsSocket = { } } }; +var clients = []; var SocketServer = { connections: [], events: { @@ -66,6 +76,62 @@ var SocketServer = { var self = this; io = sio.listen( app ); + io.sockets.on( 'connection', function (socket) { + console.log( 'Client connected' ); + + clients.push( socket ); + + io.sockets.emit( 'this', {will: 'be received by everyone'} ); + + socket.on( 'disconnect', function () { + io.sockets.emit( 'user disconnected' ); + } ); + + socket.emit( 'msg', { + datetime: new Date(), + id: socket.id, + message: "Welcome " + socket.id + " your the #" + clients.length + " socket." + } ); + + //Send custom event to client + socket.on( 'msgEvent', function (data, fn) { + console.log( 'Client message', data ); + fn( { + id: socket.id, + datetime: new Date(), + message: data + } ); + } ); + + socket.on( 'set nickname', function (name) { + socket.set( 'nickname', name, function () { + socket.emit( 'ready' ); + } ); + } ); + + socket.on( 'msg', function () { + socket.get( 'nickname', function (err, name) { + console.log( 'Chat message by ', name ); + } ); + } ); + + //Setup auto push after interval + var delayedSocketPush = delay( function (msg) { + socket.emit( 'msg', { + datetime: new Date(), + message: msg, + id: 'Server' + } ); + }, 5000 ); + + var resultPromise = delayedSocketPush( 'Here is some streaming data....' ); + + resultPromise( function (value) { + + } ); + + } ); + io.configure( function () { io.set( 'authorization', function (handshakeData, callback) { if (handshakeData.xdomain) { @@ -80,7 +146,7 @@ var SocketServer = { //Handle when a client is connected. io.sockets.on( 'connection', function (socket) { - console.warn('connection', socket); + console.warn( 'connection', socket ); //push to connections array self.connections.push( socket ); From 93f09846f9f6d200fce114ba58e00b1cdaa3a345 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 09:47:16 -0800 Subject: [PATCH 24/39] update --- README.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index b4e638e..cd5a442 100755 --- a/README.md +++ b/README.md @@ -9,14 +9,16 @@ This is a boilerplate CMS built with Angular, Twitter Bootstrap and Node; it is [![Coverage Status](https://coveralls.io/repos/jonniespratley/angular-cms/badge.png)](https://coveralls.io/r/jonniespratley/angular-cms) - [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/jonniespratley/angular-cms/trend.png)](https://bitdeli.com/free) - [![Dependency Status](https://david-dm.org/jonniespratley/angular-cms.svg)](https://david-dm.org/jonniespratley/angular-cms) +[![Code Climate](https://codeclimate.com/github/jonniespratley/angular-cms/badges/gpa.svg)](https://codeclimate.com/github/jonniespratley/angular-cms) + +[![Test Coverage](https://codeclimate.com/github/jonniespratley/angular-cms/badges/coverage.svg)](https://codeclimate.com/github/jonniespratley/angular-cms) + ### Technologies Some featured technologies used in this project include the following: @@ -75,13 +77,13 @@ To run the application on your local machine please take the following steps. To start mongodb execute the following command: -<<<<<<< HEAD +\<\<\<\<\<\<< HEAD + ``` $ sh ./bin/db.sh ``` -======= - $ sh ./bin/db.sh ->>>>>>> fe4af0e14ef3596c823d4777d672ba00406ddb90 + +======= $ sh ./bin/db.sh >>>>>>> fe4af0e14ef3596c823d4777d672ba00406ddb90 > **Note:** If errors when executing command remove the `db/mongod.lock` file. @@ -140,13 +142,17 @@ $ grunt protractor --- -<<<<<<< HEAD +\<\<\<\<\<\<< HEAD + RESTful Server -------------- + ======= -## RESTful Server -The server is a Node.js server that supports dynamic RESTful API calls to resource endpoints. It will automatically create a database if it does not exist and collection(s). ->>>>>>> fe4af0e14ef3596c823d4777d672ba00406ddb90 + +RESTful Server +-------------- + +The server is a Node.js server that supports dynamic RESTful API calls to resource endpoints. It will automatically create a database if it does not exist and collection(s). >>>>>>> fe4af0e14ef3596c823d4777d672ba00406ddb90 The server is a Node.js server that supports dynamic RESTful API calls to resource endpoints. It will automatically create a database if it does not exist and collection(s). @@ -208,22 +214,23 @@ my-theme/ content.html ``` - - --- -## Plugins +Plugins +------- + Plugins will be installed via `bower`, search and install themes searching by tag `angular-cms`. ### Structure of plugin - --- -## API Documentation +API Documentation +----------------- + The API documentation will be in the form of ngDocs style. The files located in the `content` directory are tutorial specs for the different features in this project. Documentation can be generated and viewed by running the following command: -``` +\`\`\` $ grunt docs\`\`\` From d621dbbc56fca020c4b0f1abc64e49d93d92fcad Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 11:10:13 -0800 Subject: [PATCH 25/39] updated dependencies --- Gruntfile.js | 2 +- config/config.json | 2 +- package.json | 8 +- routes/cms-auth.js | 139 +++++++++++++++++++---------------- routes/rest.js | 136 +++++++++++++++++++--------------- test/routes/rest-spec.coffee | 7 +- test/routes/rest-spec.js | 93 ++++++++++++----------- 7 files changed, 211 insertions(+), 176 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 70ea7cd..9883f61 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -601,7 +601,7 @@ module.exports = function (grunt) { clearRequireCache: false // Optionally clear the require cache before running tests (defaults to false) }, src: [ - '.tmp/routes/*-spec.js' + 'test/routes/*-spec.js' ] } } diff --git a/config/config.json b/config/config.json index c71b0f8..fe6fce0 100644 --- a/config/config.json +++ b/config/config.json @@ -4,7 +4,7 @@ "apiBase": "/api/v2", "version": "v2", "security": {"salt": ""}, - "mongodb": "angularcms:angularcms@paulo.mongohq.com:10089/app19632340", + "mongodb": "localhost:27017/angular-cms", "db": { "name": "angular-cms", "username": "amadmin", diff --git a/package.json b/package.json index 45be60f..b038b0a 100755 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "yeoman" ], "dependencies": { + "bcrypt-nodejs": "0.0.3", "body-parser": "^1.9.3", "body-parser-json": "^1.9.2", "colors": "~0.6.2", @@ -35,10 +36,10 @@ "ejs": "^1.0.0", "ejs-locals": "^1.0.2", "emailjs": "~0.3.6", - "express": "~3.4.6", - "express-flash": "0.0.2", + "express": "~4.0.0", "express-session": "^1.9.3", - "fs-extra": "^0.12.0", + "method-override": "~1.0.0", + "fs-extra": "^0.12.0", "http-proxy": "^1.3.0", "jps-ds": "~0.0.2", "jquery": "~2.1.0", @@ -48,7 +49,6 @@ "logfmt": "~0.18.1", "markdown": "~0.5.0", "mongodb": "*", - "mongoose": "*", "npmlog": "^0.1.1", "passport": "^0.2.1", "passport-facebook": "^1.0.3", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 0800198..37a3d55 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -10,9 +10,13 @@ var passport = require('passport'), DS = require('jps-ds').DS; -var session = require('express-session') + var cookieParser = require('cookie-parser'); -var bodyParser = require('body-parser'); +var bodyParser = require('body-parser'); +var session = require('express-session'); + + +var router = express.Router(); var users = [ {id: 1, username: 'admin', password: 'admin', email: 'admin@gmail.com'}, @@ -20,15 +24,16 @@ var users = [ {id: 3, username: 'jonniespratley', password: 'fred', email: 'jonniespratley@gmail.com'} ]; -var User = function(){}; +var User = function () { +}; -User.findOrCreate = function(profile, fn){ +User.findOrCreate = function (profile, fn) { console.warn('findOrCreate', profile); - User.findByEmail(profile.emails[0], function(err, user){ + User.findByEmail(profile.emails[0], function (err, user) { fn(user); }); }; -User.findById = function(id, fn) { +User.findById = function (id, fn) { var idx = id - 1; console.warn('findById', id); if (users[idx]) { @@ -37,7 +42,7 @@ User.findById = function(id, fn) { fn(new Error('User ' + id + ' does not exist')); } }; -User.findByUsername = function(username, fn) { +User.findByUsername = function (username, fn) { var defer = q.defer(); console.warn('findByUsername', username); for (var i = 0, len = users.length; i < len; i++) { @@ -50,7 +55,7 @@ User.findByUsername = function(username, fn) { } return defer.promise; }; -User.findByEmail = function(email, fn) { +User.findByEmail = function (email, fn) { console.warn('findByEmail', email); for (var i = 0, len = users.length; i < len; i++) { var user = users[i]; @@ -61,7 +66,14 @@ User.findByEmail = function(email, fn) { return fn(null, null); }; -function cmsAuth(options, app) { + +/** + * I am the cmsAuth module + * @param options + * @param app + * @returns {*} + */ +var cmsAuth = function(options, app) { var self = this; var baseUrl = options.host + ':' + options.port; if (!app) { @@ -87,18 +99,18 @@ function cmsAuth(options, app) { // this will be as simple as storing the user ID when serializing, and finding // the user by ID when deserializing. - passport.serializeUser(function(user, done) { - done(null, user.id); + passport.serializeUser(function (user, done) { + done(null, user.id); }); - passport.deserializeUser(function(id, done) { - User.findById(id, function(err, user) { - done(err, user); - }); + passport.deserializeUser(function (id, done) { + User.findById(id, function (err, user) { + done(err, user); + }); }); -/* */ + /* */ // Strategies in passport require a `verify` function, which accept // credentials (in this case, a username and password), and invoke a callback @@ -110,82 +122,78 @@ function cmsAuth(options, app) { }, function (username, password, done) { process.nextTick(function () { console.warn('find by username'); - User.findByUsername(username).then(function(user){ + User.findByUsername(username).then(function (user) { return done(null, user); - }, function(err){ + }, function (err) { return done(null, false); }); }); } )); -/**/ + /**/ passport.use(new GoogleStrategy({ returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' }, function (identifier, profile, done) { - console.warn( 'googleCallback', profile); + console.warn('googleCallback', profile); profile.openId = identifier; - User.findOrCreate(profile, function(err, user) { - done(err, user); - }); + User.findOrCreate(profile, function (err, user) { + done(err, user); + }); } )); - //Setup - app.configure(function () { - app.use(express.logger()); - 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(express.cookieParser()); - app.use(express.methodOverride()); - app.use(bodyParser.urlencoded({extended: false})); - app.use(bodyParser.json()); - app.use("jsonp callback", true); - app.use(flash()); - app.use(session({ - secret: 'angular-cms', - resave: true, - saveUninitialized: true - })); - app.use(passport.initialize()); - app.use(passport.session()); - app.use(app.router); - }); - - app.get('/api/me', passport.authenticate('basic', { session: false }), function(req, res) { - res.json(req.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({ + 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.get('/', function(req, res){ - res.render('index', { user: req.user, message: 'Please login', status: 'info' }); + 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('/account', ensureAuthenticated, function (req, res) { + res.render('account', {user: req.user}); }); - app.get('/login', function(req, res){ - res.render('login', { user: req.user, message: 'Please login', status: 'warning' }); + app.get('/login', function (req, res) { + res.render('login', {user: req.user, message: 'Please login', status: 'warning'}); }); -app.post('/login', - passport.authenticate('local', { successRedirect: '/', - failureRedirect: '/login', - failureFlash: false }) -); + app.post('/login', + passport.authenticate('local', { + successRedirect: '/', + failureRedirect: '/login', + failureFlash: false + }) + ); app.get('/auth/user', ensureAuthenticated, function (req, res) { res.json(200, req.user); @@ -200,20 +208,21 @@ app.post('/login', // Redirect the user to Google for authentication. When complete, Google // will redirect the user back to the application at // /auth/google/return -app.get('/auth/google', passport.authenticate('google')); + app.get('/auth/google', passport.authenticate('google')); // Google will redirect the user to this URL after authentication. Finish // the process by verifying the assertion. If valid, the user will be // logged in. Otherwise, authentication has failed. -app.get('/auth/google/return', - passport.authenticate('google', { successRedirect: '/', - failureRedirect: '/login' })); + app.get('/auth/google/return', + passport.authenticate('google', { + successRedirect: '/', + failureRedirect: '/login' + })); app.get('/auth/logout', function (req, res) { req.logout(); res.redirect('/'); }); - return app; }; diff --git a/routes/rest.js b/routes/rest.js index d7c9c4a..9a0e1eb 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -42,6 +42,7 @@ var MESSAGES = { var DS = require('jps-ds').DS; var _ds = new DS({ host: 'angularcms:angularcms@paulo.mongohq.com:10089/app19632340', + //host: 'localhost:27017/angular-cms', models: { 'groups': { title: String, @@ -51,6 +52,12 @@ var _ds = new DS({ updated: Date }, 'users': { + id: String, + provider: String, + displayName: String, + name: Object, + emails: Array, + photos: Array, username: String, email: String, password: String, @@ -174,7 +181,7 @@ var RestResource = { v1: 'https://www..com', v2: '/api/v2/' }, - log: function(){ + log: function () { console.log(util.inspect(arguments, {colors: true})); }, @@ -194,25 +201,28 @@ var RestResource = { */ login: function (req, res, next) { var query = {}; - console.log(req.body); - //TODO: Need to make this externalized. if (req.body.username) { query.username = req.body.username; } if (req.body.email) { - query.email = req.body.email; + query.username = req.body.email; } //TODO: Hashing on client side - query.password = hashPassword(req.body.password, req.body.email); + query.password = hashPassword(req.body.password, query.username); - console.log('Login Query: ', query); + console.warn('Login Query: ' + JSON.stringify(query) + ''.verbose); _ds.findOne('users', query).then(function (data) { - res.json(200, data); + if (data) { + res.jsonp(200, data); + } else { + res.jsonp(404, {message: 'Wrong username/password!'}); + } + }, function (err) { - res.json(400, err); + res.jsonp(400, err); }); @@ -224,13 +234,25 @@ var RestResource = { * @param next */ register: function (req, res, next) { - var data = req.body, - user = null, - query = { - email: req.body.email - }; - data.password = hashPassword(req.body.password, req.body.email), - console.log(String("Register user").debug, req.body); + var data = req.body; + + //TODO: Need to make this externalized. + if (req.body.username) { + data.username = req.body.username; + } + if (req.body.email) { + data.username = req.body.email; + } + + //TODO: Hashing on client side + data.password = hashPassword(req.body.password, data.username); + + _ds.create('users', data).then(function (user) { + res.json(201, user); + }, function (err) { + res.json(400, err); + }); + // console.log(String("Register user").debug, query); }, session: function (req, res, next) { }, @@ -409,9 +431,6 @@ var RestResource = { }; - - - //### getFile //Get file contents from a file. function getFile(localPath, mimeType, res) { @@ -446,7 +465,6 @@ function writeFile(localPath, contents) { }; - var config = {}; var publicPath = config.publicDir; var uploadsTmpDir = config.uploadsTmpDir; @@ -466,69 +484,65 @@ var cmsRest = function (options) { config = options; - + var router = express.Router(); //### Express Config //Configure the express app server. //### modules //Gather all of the files and folders in the app/modules directory - app.get(config.apiBase + '/plugins', RestResource.plugins); + router.get(config.apiBase + '/plugins', RestResource.plugins); //# Routes //### v2 API - app.get(config.apiBase + '/readme', RestResource.readme); + router.get(config.apiBase + '/readme', RestResource.readme); //v2 mongo rest api - app.get(config.apiBase, RestResource.index); - app.post(config.apiBase + '/upload', RestResource.upload); - app.get(config.apiBase + '/upload', function(req, res, next){ + router.get(config.apiBase, RestResource.index); + router.post(config.apiBase + '/upload', RestResource.upload); + router.get(config.apiBase + '/upload', function (req, res, next) { res.send({message: 'Upload a file with a POST.'}); }); //Always users table - app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); - app.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); - app.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); + router.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); + router.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); + router.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); //Dynamic REST - app.get(config.apiBase + '/:db/:collection/:id?', RestResource.get); - app.post(config.apiBase + '/:db/:collection', bodyParser.json(), RestResource.add); - app.put(config.apiBase + '/:db/:collection/:id', bodyParser.json(), RestResource.edit); - app.delete(config.apiBase + '/:db/:collection/:id', RestResource.destroy); - - - app.configure(function () { - app.set("view options", {layout: false, pretty: true}); - app.use(express.static(config.staticDir)); - app.use(express.directory(config.publicDir)); - app.use(bodyParser.json()); - app.use(bodyParser.urlencoded()); - app.use("jsonp callback", true); - - app.use(config.apiBase + '/upload2', upload.fileHandler()); - app.use(app.router); - }); + router.route(config.apiBase + '/:db/:collection/:id?') + .all(function (req, res, next) { + console.warn('REST ', req.param('collection')); + }) + .get(RestResource.get) + .post(bodyParser.json(), RestResource.add) + .put(bodyParser.json(), RestResource.edit) + .delete(RestResource.destroy); + + router.use(bodyParser.json()); + router.use(bodyParser.urlencoded({extended: false})); + router.use(config.apiBase + '/upload2', upload.fileHandler()); + + // default options, immediately start reading from the request stream and // parsing -app.use(busboy({ immediate: true })); + router.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 ... - } -}); - + router.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 ... + } + }); - return app; + return router; }; module.exports = cmsRest; diff --git a/test/routes/rest-spec.coffee b/test/routes/rest-spec.coffee index a491d2c..616e3b4 100644 --- a/test/routes/rest-spec.coffee +++ b/test/routes/rest-spec.coffee @@ -1,12 +1,13 @@ #Routes Spec request = require('supertest') +path = require('path') expect = require('chai').expect #//Dynamic rest server -rest = require(__dirname + '/routes/rest').rest +rest = require(path.resolve(__dirname, '../../routes/rest.js')).rest console.log(__dirname) -app = rest.init({port: 9191}); +app = new rest({port: 9191}); endpoint = 'http://localhost:8181/api/v2' postData = @@ -28,4 +29,4 @@ describe 'Testing: API Server', () -> request(app) .get '/api/v2/angular-cms/users' .expect "Content-Type", /json/ - .expect 200, done \ No newline at end of file + .expect 200, done diff --git a/test/routes/rest-spec.js b/test/routes/rest-spec.js index ff326fa..b66d98d 100644 --- a/test/routes/rest-spec.js +++ b/test/routes/rest-spec.js @@ -1,55 +1,66 @@ -/** - * Created by jonniespratley on 11/27/14. - */ -var app, endpoint, expect, postData, request, rest; - +var app, endpoint, expect, path, postData, request, rest; request = require('supertest'); +path = require('path'); +fs = require('fs'); expect = require('chai').expect; -rest = require('../../routes/rest').rest; - -app = rest.init({ - port: 9191, - 'staticDir': '/dist', - 'publicDir': '/app', - 'uploadsTmpDir': '/.tmp', - 'uploadsDestDir': '/www/cms-content/uploads', - 'uploadsUrl': ':8181/cms-content/', - 'logFormat': '[:date] - [:method] - :url - :status - :response-time ms', - 'db': { - 'name': 'angular-cms', - 'username': 'amadmin', - 'password': 'fred', - 'host': 'localhost', - 'port': 27017 - } +var config = JSON.parse(fs.readFileSync(process.cwd() + '/config/config.json')); +config.port = 9191 +var cmsAuth = require(process.cwd() + '/routes/cms-auth'); +var cmsRest = require(process.cwd() + '/routes/rest'); +var rest = new cmsRest(config); +var auth = new cmsAuth(config, rest); +auth.listen(config.port || process.env.PORT, function () { + console.log(String('Node.js REST server listening on port: ' + config.port).verbose); }); 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' + "username": "nodetest" + Date.now(), + "email": "nodetest@email.com", + "password": "test", + "active": true, + "groups": ["member"], + "created": new Date(), + "modified": new Date(), + "metadata": { + "avatar": "", + "name": "Node Test User" } }; describe('Testing: API Server', function () { - describe('GET /users', function () { - it('respond with json', function (done) { - request(app) - .get('/api/v2/angular-cms/users') - .expect('Content-Type', /json/) - .expect(200, done); - }); + + it('POST - /api/v2/users/register - should return user on successful registation', function (done) { + request(auth) + .post('/api/v2/users/register') + .send(postData) + .expect("Content-Type", /json/) + .expect(201, done); }); + + it('POST - /api/v2/users/login - should return user on successful login', function (done) { + var validUser = { + username: 'nodetest', + password: 'test' + }; + request(auth) + .post('/api/v2/users/login') + .send(validUser) + .expect("Content-Type", /json/) + .expect(200, done); + }); + it('POST - /api/v2/users/login - should return false on unsuccessful login', function (done) { + var invalidUser = { + username: 'test1', + password: 'wrongpassword' + }; + request(auth) + .post('/api/v2/users/login') + .send(invalidUser) + .expect("Content-Type", /json/) + .expect(404, done); + }); + }); From 339261d570c2810b9e6074fa7c3427bdc5a92e6d Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 13:31:30 -0800 Subject: [PATCH 26/39] updated auth --- routes/cms-auth.js | 1 - 1 file changed, 1 deletion(-) diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 37a3d55..7928294 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -16,7 +16,6 @@ var bodyParser = require('body-parser'); var session = require('express-session'); -var router = express.Router(); var users = [ {id: 1, username: 'admin', password: 'admin', email: 'admin@gmail.com'}, From 7964a53bc3ed83724e6ae359fdf535b1d1eec418 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 13:34:46 -0800 Subject: [PATCH 27/39] updated ignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9791eff..48ad01b 100755 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ node_modules .idea .grunt .sass-cache -.editorconfig .project app/bower_components coverage/ @@ -18,4 +17,4 @@ coverage/ atlassian-ide-plugin.xml docs dist -.c9 \ No newline at end of file +.c9 From fc3c6cd7d06dd413d23f1253f6758b9e0dbddf3c Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Mon, 8 Dec 2014 14:43:31 -0800 Subject: [PATCH 28/39] added routes --- config/config.json | 4 + package.json | 1 - routes/cms-auth.js | 221 +--------------------- routes/cms-passport.js | 163 +++++++++++++++++ routes/cms-proxy.js | 3 + routes/cms-rest.js | 23 +++ routes/cms-routes.js | 1 + routes/cms-server.js | 3 + routes/cms-sockets.js | 3 + routes/cms-upload.js | 127 +++++++++++++ routes/codegen.js | 102 ----------- routes/models/user.js | 42 +++++ routes/rest.js | 181 +----------------- routes/server.coffee | 170 ----------------- routes/smartpass.js | 387 --------------------------------------- routes/socketserver.js | 3 +- server.js | 55 +++--- test/routes/rest-spec.js | 36 ++-- 18 files changed, 418 insertions(+), 1107 deletions(-) create mode 100644 routes/cms-passport.js create mode 100644 routes/cms-proxy.js create mode 100644 routes/cms-rest.js create mode 100644 routes/cms-routes.js create mode 100644 routes/cms-server.js create mode 100644 routes/cms-sockets.js create mode 100644 routes/cms-upload.js delete mode 100644 routes/codegen.js create mode 100644 routes/models/user.js delete mode 100644 routes/server.coffee delete mode 100644 routes/smartpass.js diff --git a/config/config.json b/config/config.json index fe6fce0..c4e1e82 100644 --- a/config/config.json +++ b/config/config.json @@ -16,6 +16,10 @@ "username": "angular.cms@gmail.com", "password": "isyourdaughter18?" }, + "proxy": { + "hostname": "localhost", + "port": 5001 + }, "staticDir": "/dist", "publicDir": "/app", "uploadsTmpDir": "/.tmp", diff --git a/package.json b/package.json index b038b0a..a3e03b5 100755 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "logfmt": "~0.18.1", "markdown": "~0.5.0", "mongodb": "*", - "npmlog": "^0.1.1", "passport": "^0.2.1", "passport-facebook": "^1.0.3", "passport-google": "^0.3.0", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 7928294..963b606 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -3,227 +3,12 @@ var passport = require('passport'), BasicStrategy = require('passport-http').Strategy, LocalStrategy = require('passport-local').Strategy, GoogleStrategy = require('passport-google').Strategy, - log = require('npmlog'), path = require('path'), q = require('q'), flash = require('express-flash'), DS = require('jps-ds').DS; - -var cookieParser = require('cookie-parser'); -var bodyParser = require('body-parser'); -var session = require('express-session'); - - - -var users = [ - {id: 1, username: 'admin', password: 'admin', email: 'admin@gmail.com'}, - {id: 2, username: 'test', password: 'test', email: 'test@gmail.com'}, - {id: 3, username: 'jonniespratley', password: 'fred', email: 'jonniespratley@gmail.com'} -]; - -var User = function () { -}; - -User.findOrCreate = function (profile, fn) { - console.warn('findOrCreate', profile); - User.findByEmail(profile.emails[0], function (err, user) { - fn(user); - }); -}; -User.findById = function (id, fn) { - var idx = id - 1; - console.warn('findById', id); - if (users[idx]) { - fn(null, users[idx]); - } else { - fn(new Error('User ' + id + ' does not exist')); - } -}; -User.findByUsername = function (username, fn) { - var defer = q.defer(); - console.warn('findByUsername', username); - for (var i = 0, len = users.length; i < len; i++) { - var user = users[i]; - if (user.username === username) { - defer.resolve(user); - } else { - console.warn('user not found', username); - } - } - return defer.promise; -}; -User.findByEmail = function (email, fn) { - console.warn('findByEmail', email); - for (var i = 0, len = users.length; i < len; i++) { - var user = users[i]; - if (user.email === email) { - return fn(null, user); - } - } - return fn(null, null); -}; - - -/** - * I am the cmsAuth module - * @param options - * @param app - * @returns {*} - */ -var cmsAuth = function(options, app) { - var self = this; - var baseUrl = options.host + ':' + options.port; - if (!app) { - throw new Error('Must provide express application!'); - } - - -// Simple route middleware to ensure user is authenticated. -// Use this route middleware on any resource that needs to be protected. If -// the request is authenticated (typically via a persistent login session), -// the request will proceed. Otherwise, the user will be redirected to the -// login page. - function ensureAuthenticated(req, res, next) { - if (req.isAuthenticated()) { - return next(); - } - res.redirect('/login'); - } - -// Passport session setup. -// To support persistent login sessions, Passport needs to be able to -// serialize users into and deserialize users out of the session. Typically, -// this will be as simple as storing the user ID when serializing, and finding -// the user by ID when deserializing. - - passport.serializeUser(function (user, done) { - done(null, user.id); - }); - - passport.deserializeUser(function (id, done) { - User.findById(id, function (err, user) { - done(err, user); - }); - }); - - - /* */ - -// Strategies in passport require a `verify` function, which accept -// credentials (in this case, a username and password), and invoke a callback -// with a user object. In the real world, this would query a database; -// however, in this example we are using a baked-in set of users. - passport.use(new LocalStrategy({ - usernameField: 'email', - passwordField: 'password' - }, 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); - }); - }); - } - )); - - /**/ - passport.use(new GoogleStrategy({ - returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' - }, - function (identifier, profile, done) { - console.warn('googleCallback', profile); - profile.openId = identifier; - User.findOrCreate(profile, function (err, user) { - done(err, user); - }); - } - )); - - - //Setup - - - 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({ - 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.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('/login', function (req, res) { - res.render('login', {user: req.user, message: 'Please login', status: 'warning'}); - }); - - - app.post('/login', - passport.authenticate('local', { - successRedirect: '/', - failureRedirect: '/login', - failureFlash: false - }) - ); - - app.get('/auth/user', ensureAuthenticated, function (req, res) { - res.json(200, req.user); - }); - - app.get('/auth/logout', function (req, res) { - req.logout(); - res.redirect(options.apiBase); - }); - - - // Redirect the user to Google for authentication. When complete, Google -// will redirect the user back to the application at -// /auth/google/return - app.get('/auth/google', passport.authenticate('google')); - -// Google will redirect the user to this URL after authentication. Finish -// the process by verifying the assertion. If valid, the user will be -// logged in. Otherwise, authentication has failed. - app.get('/auth/google/return', - passport.authenticate('google', { - successRedirect: '/', - failureRedirect: '/login' - })); - app.get('/auth/logout', function (req, res) { - req.logout(); - res.redirect('/'); - }); - - return app; -}; - - -module.exports = cmsAuth; + module.exports = function(config, app){ + console.warn('cms-auth'); + }; diff --git a/routes/cms-passport.js b/routes/cms-passport.js new file mode 100644 index 0000000..c88cf00 --- /dev/null +++ b/routes/cms-passport.js @@ -0,0 +1,163 @@ +var passport = require('passport'), + BasicStrategy = require('passport-http').Strategy, + LocalStrategy = require('passport-local').Strategy, + GoogleStrategy = require('passport-google').Strategy, + log = require('npmlog'), + express = require('express'), + path = require('path'), + q = require('q'), + flash = require('express-flash'), + User = require('./models/user'), + cookieParser = require('cookie-parser'), + bodyParser = require('body-parser'), + session = require('express-session'); + + +module.exports = function(config, app){ + + + if (!app) { + throw new Error('Must provide express application!'); + } + + + // Simple route middleware to ensure user is authenticated. + // Use this route middleware on any resource that needs to be protected. If + // the request is authenticated (typically via a persistent login session), + // the request will proceed. Otherwise, the user will be redirected to the + // login page. + function ensureAuthenticated(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + res.redirect('/login'); + } + + // Passport session setup. + // To support persistent login sessions, Passport needs to be able to + // serialize users into and deserialize users out of the session. Typically, + // this will be as simple as storing the user ID when serializing, and finding + // the user by ID when deserializing. + + passport.serializeUser(function (user, done) { + done(null, user.id); + }); + + passport.deserializeUser(function (id, done) { + User.findById(id, function (err, user) { + done(err, user); + }); + }); + + + /* */ + + // Strategies in passport require a `verify` function, which accept + // credentials (in this case, a username and password), and invoke a callback + // with a user object. In the real world, this would query a database; + // however, in this example we are using a baked-in set of users. + passport.use(new LocalStrategy({ + usernameField: 'email', + passwordField: 'password' + }, 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); + }); + }); + } +)); + + /**/ + passport.use(new GoogleStrategy({ + returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' + }, + function (identifier, profile, done) { + console.warn('googleCallback', profile); + profile.openId = identifier; + 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({ + 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.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('/login', function (req, res) { + res.render('login', {user: req.user, message: 'Please login', status: 'warning'}); + }); + + + app.post('/login', + passport.authenticate('local', { + successRedirect: '/', + failureRedirect: '/login', + failureFlash: false + }) +); + +app.get('/auth/user', ensureAuthenticated, function (req, res) { + res.json(200, req.user); +}); + +app.get('/auth/logout', function (req, res) { + req.logout(); + res.redirect(options.apiBase); +}); + + +// Redirect the user to Google for authentication. When complete, Google +// will redirect the user back to the application at +// /auth/google/return +app.get('/auth/google', passport.authenticate('google')); + +// Google will redirect the user to this URL after authentication. Finish +// the process by verifying the assertion. If valid, the user will be +// logged in. Otherwise, authentication has failed. +app.get('/auth/google/return', +passport.authenticate('google', { + successRedirect: '/', + failureRedirect: '/login' +})); +app.get('/auth/logout', function (req, res) { + req.logout(); + res.redirect('/'); +}); + +} diff --git a/routes/cms-proxy.js b/routes/cms-proxy.js new file mode 100644 index 0000000..b7698cd --- /dev/null +++ b/routes/cms-proxy.js @@ -0,0 +1,3 @@ +module.exports = function(config, app){ + console.warn('cms-proxy', config, app); +}; diff --git a/routes/cms-rest.js b/routes/cms-rest.js new file mode 100644 index 0000000..cab2aa4 --- /dev/null +++ b/routes/cms-rest.js @@ -0,0 +1,23 @@ +var cookieParser = require('cookie-parser'), + bodyParser = require('body-parser'), + session = require('express-session'), + RestResource = require('./rest'); + +module.exports = function (config, app) { + "use strict"; + + app.get(config.apiBase + '/plugins', RestResource.plugins); + app.get(config.apiBase + '/readme', RestResource.readme); + app.get(config.apiBase, RestResource.index); + + //Always users table + app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); + app.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); + app.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); + + //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); +}; diff --git a/routes/cms-routes.js b/routes/cms-routes.js new file mode 100644 index 0000000..ac952c3 --- /dev/null +++ b/routes/cms-routes.js @@ -0,0 +1 @@ +module.exports.mount = function(config, 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); }; \ No newline at end of file diff --git a/routes/cms-server.js b/routes/cms-server.js new file mode 100644 index 0000000..b7698cd --- /dev/null +++ b/routes/cms-server.js @@ -0,0 +1,3 @@ +module.exports = function(config, app){ + console.warn('cms-proxy', config, app); +}; diff --git a/routes/cms-sockets.js b/routes/cms-sockets.js new file mode 100644 index 0000000..b7698cd --- /dev/null +++ b/routes/cms-sockets.js @@ -0,0 +1,3 @@ +module.exports = function(config, app){ + console.warn('cms-proxy', config, app); +}; diff --git a/routes/cms-upload.js b/routes/cms-upload.js new file mode 100644 index 0000000..0fd04ac --- /dev/null +++ b/routes/cms-upload.js @@ -0,0 +1,127 @@ +var easyimage = require('easyimage'); +var upload = require('jquery-file-upload-middleware'); +var fs = require('fs-extra'); +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 ... + } + }); + + + + //### upload + //I handled processing a uploaded file on the v2 server. + var upload = function (req, res, next) { + var appid = 'public'; + + if (req.param('appid')) { + appid = String(req.param('appid')); + } + + console.log(util.inspect(req, {colors: true})); + + //Handle if dynamic filenames are enabled + var tmp_filename = req.files.file.name || 'tmp_name'; + var filename = tmp_filename; + var tmp_path = req.files.file.path; + var target_dir = config.uploadsDestDir + '/' + appid + '/'; + var target_path = config.uploadsDestDir + '/' + appid + '/' + filename; + var thumb_dir = config.uploadsDestDir + '/' + appid + '/thumbnail/'; + var thumb_path = config.uploadsDestDir + '/' + appid + '/thumbnail/' + filename; + + //Get the params for cropping an image + var x1 = req.body.x1, y1 = req.body.y1, x2 = req.body.x2, y2 = req.body.y2, height = req.body.height, width = req.body.width, filepath = target_path; + + if (!width) { + width = 150; + } + + //Log the vars + console.log(x1, x2, y1, y2, height, width, thumb_path); + + //Orignal image + console.log(String('Temp Path: ' + tmp_path).warn); + console.log(String('Target Dir: ' + target_dir).warn); + console.log(String('Target Path: ' + target_path).warn); + + //Thumbnail image + console.log(String('Original File: ' + filename).debug); + console.log(String('Original File Path: ' + target_path).debug); + console.log(String('Thumb Dir: ' + thumb_dir).debug); + console.log(String('Thumb Path: ' + thumb_path).debug); + + //Create the directory and move the file to that directory + fs.mkdir(target_dir, 0777, function (e) { + + //Rename the file + fs.rename(tmp_path, target_path, function (err) { + if (err) { + console.error('File Rename Error:', err); + } + + //Create the thumb directory + fs.mkdir(thumb_dir, 0777, function (e) { + + //Create the thumbnail from the default image + var imgOptions = { + src: target_path, + dst: thumb_path, + width: width, + height: height, + quality: 100, + x: x1, + y: y1 + }; + + //Resize the image + easyimg.resize(imgOptions, function (e) { + console.log('easyimg', imgOptions, e); + req.files.file.target_dir = target_dir; + req.files.file.target_path = target_path; + req.files.file.thumb_path = thumb_path; + req.files.file.thumb_dir = thumb_dir; + req.files.file.filename = filename; + + //build the response object + var json = { + status: true, + filename: filename, + targetDir: target_dir, + targetPath: target_path, + thumbDir: thumb_dir, + thumbPath: thumb_path, + msg: 'File Uploaded', + results: req.files, + appid: appid + }; + + //Output the results + res.send(json); + }); + }); + }); + }); + }; + + app.post(config.apiBase + '/upload', upload); + app.get(config.apiBase + '/upload', function (req, res, next) { + res.send({message: 'Upload a file with a POST.'}); + }); + +}; diff --git a/routes/codegen.js b/routes/codegen.js deleted file mode 100644 index 1382cc8..0000000 --- a/routes/codegen.js +++ /dev/null @@ -1,102 +0,0 @@ -/** - * This is the javascript version of the CodeGen controller that is written in php. - * - * CodeGen Package -The CodeGen Packager creates files for generating, compiling, running, testing, packaging, deploying and downloading the application. - -The following shell files are created in this order: - -1. generate.sh - This file generate the project files based on the config.json file and converts the project into a Titanium Mobile + Alloy application. -2. compile.sh - This file compiles the newly generated project files into a ios/android application. -3. run.sh - This file runs the newly compiled code in the os simulator. -4. test.sh - This file uploads the compiled code to Testflight.com for distribution to test devices. -5. package.sh - This file packages the app into a .ipa, .achive and a .apk for distribution. -6. deploy.sh - This file then deploys the application to the various app marketplaces. -7. project.zip - This is a archive file of your compiled application and all project files, .ipa, .apk, etc. - - -The packager assumes the following paths are set as well: - -Titanium SDK: -/Users/jonniespratley/Library/Application Support/Titanium/ - - -Android SDK: -/WWW/SDKs/android-sdk-macosx - - - -iOS SDK: -/Applications/Xcode.app/Contents/Developer - - - - - - -Tools for generating pems, passbooks, etc. - - - - - - - */ - - -//Get file contents from a file -function getFile (localPath, mimeType, res) { - fs.readFile(localPath, function (err, contents) { - if (!err) { - res.writeHead(200, { - "Content-Type" : mimeType, - "Content-Length" : contents.length - }); - res.end(contents); - } else { - res.writeHead(500); - res.end(); - } - }); -}; - - -//Write contents to a file -function writeFile (localPath, contents) { - // create a stream, and create the file if it doesn't exist - stream = fs.createWriteStream(localPath); - console.log('writeFile', localPath); - stream.on("open", function () { - // write to and close the stream at the same time - stream.end(contents, 'utf-8'); - res.end(html); - }); -}; - - - - -/** - * Command Server for executing build commands from the Web app. - */ -var sys = require('sys') -var exec = require('child_process').exec; -var child; - -rest.app.get('/pwd', function(req, res) { - var results = {}; - - child = exec("pwd", function(error, stdout, stderr) { - - results.stdout = stdout; - - - res.header('Content-Type', 'application/json'); - res.send(JSON.stringify(results), 200); - sys.print('stdout: ' + stdout); - - if (error !== null) { - console.log('exec error: ' + error); - } - }); -}); diff --git a/routes/models/user.js b/routes/models/user.js new file mode 100644 index 0000000..b95ac34 --- /dev/null +++ b/routes/models/user.js @@ -0,0 +1,42 @@ + +var User = function () {}; + +User.findOrCreate = function (profile, fn) { + console.warn('findOrCreate', profile); + User.findByEmail(profile.emails[0], function (err, user) { + fn(user); + }); +}; +User.findById = function (id, fn) { + var idx = id - 1; + console.warn('findById', id); + if (users[idx]) { + fn(null, users[idx]); + } else { + fn(new Error('User ' + id + ' does not exist')); + } +}; +User.findByUsername = function (username, fn) { + var defer = q.defer(); + console.warn('findByUsername', username); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.username === username) { + defer.resolve(user); + } else { + console.warn('user not found', username); + } + } + return defer.promise; +}; +User.findByEmail = function (email, fn) { + console.warn('findByEmail', email); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.email === email) { + return fn(null, user); + } + } + return fn(null, null); +}; +module.exports = User; diff --git a/routes/rest.js b/routes/rest.js index 9a0e1eb..50043f9 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -23,14 +23,14 @@ var path = require('path'); //used for file path var fs = require('fs-extra'); //File System - for file manipulatio var util = require('util'); var request = require('request'); -var easyimage = require('easyimage'); -var upload = require('jquery-file-upload-middleware'); + var sio = require('socket.io'); var Deferred = require("promised-io/promise").Deferred; var when = require("promised-io/promise"); var bodyParser = require('body-parser'); -var markdown = require("markdown").markdown; var busboy = require('connect-busboy'); //middleware for form/file upload +var markdown = require("markdown").markdown; + //Strings for results var MESSAGES = { @@ -257,99 +257,6 @@ var RestResource = { session: function (req, res, next) { }, - //### upload - //I handled processing a uploaded file on the v2 server. - upload: function (req, res, next) { - var appid = 'public'; - - if (req.param('appid')) { - appid = String(req.param('appid')); - } - - console.log(util.inspect(req, {colors: true})); - - //Handle if dynamic filenames are enabled - var tmp_filename = req.files.file.name || 'tmp_name'; - var filename = tmp_filename; - var tmp_path = req.files.file.path; - var target_dir = config.uploadsDestDir + '/' + appid + '/'; - var target_path = config.uploadsDestDir + '/' + appid + '/' + filename; - var thumb_dir = config.uploadsDestDir + '/' + appid + '/thumbnail/'; - var thumb_path = config.uploadsDestDir + '/' + appid + '/thumbnail/' + filename; - - //Get the params for cropping an image - var x1 = req.body.x1, y1 = req.body.y1, x2 = req.body.x2, y2 = req.body.y2, height = req.body.height, width = req.body.width, filepath = target_path; - - if (!width) { - width = 150; - } - - //Log the vars - console.log(x1, x2, y1, y2, height, width, thumb_path); - - //Orignal image - console.log(String('Temp Path: ' + tmp_path).warn); - console.log(String('Target Dir: ' + target_dir).warn); - console.log(String('Target Path: ' + target_path).warn); - - //Thumbnail image - console.log(String('Original File: ' + filename).debug); - console.log(String('Original File Path: ' + target_path).debug); - console.log(String('Thumb Dir: ' + thumb_dir).debug); - console.log(String('Thumb Path: ' + thumb_path).debug); - - //Create the directory and move the file to that directory - fs.mkdir(target_dir, 0777, function (e) { - - //Rename the file - fs.rename(tmp_path, target_path, function (err) { - if (err) { - console.error('File Rename Error:', err); - } - - //Create the thumb directory - fs.mkdir(thumb_dir, 0777, function (e) { - - //Create the thumbnail from the default image - var imgOptions = { - src: target_path, - dst: thumb_path, - width: width, - height: height, - quality: 100, - x: x1, - y: y1 - }; - - //Resize the image - easyimg.resize(imgOptions, function (e) { - console.log('easyimg', imgOptions, e); - req.files.file.target_dir = target_dir; - req.files.file.target_path = target_path; - req.files.file.thumb_path = thumb_path; - req.files.file.thumb_dir = thumb_dir; - req.files.file.filename = filename; - - //build the response object - var json = { - status: true, - filename: filename, - targetDir: target_dir, - targetPath: target_path, - thumbDir: thumb_dir, - thumbPath: thumb_path, - msg: 'File Uploaded', - results: req.files, - appid: appid - }; - - //Output the results - res.send(json); - }); - }); - }); - }); - }, //### get //I handle gathering records dynamically from a call to the v2 api. @@ -465,84 +372,4 @@ function writeFile(localPath, contents) { }; -var config = {}; -var publicPath = config.publicDir; -var uploadsTmpDir = config.uploadsTmpDir; -var uploadDestDir = config.uploadDestDir; - -var cmsRest = function (options) { - "use strict"; - - var app = express(); - - console.log('\n\n---------------------'.verbose); - console.log('cmsRest.js'); - console.log('email: admin@email.com '.verbose); - console.log('password: admin1234'.verbose) - console.log('---------------------\n\n'.verbose); - - - config = options; - - var router = express.Router(); - - //### Express Config - //Configure the express app server. - //### modules - //Gather all of the files and folders in the app/modules directory - router.get(config.apiBase + '/plugins', RestResource.plugins); - //# Routes - //### v2 API - router.get(config.apiBase + '/readme', RestResource.readme); - //v2 mongo rest api - router.get(config.apiBase, RestResource.index); - router.post(config.apiBase + '/upload', RestResource.upload); - router.get(config.apiBase + '/upload', function (req, res, next) { - res.send({message: 'Upload a file with a POST.'}); - }); - - - //Always users table - router.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); - router.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); - router.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); - - //Dynamic REST - router.route(config.apiBase + '/:db/:collection/:id?') - .all(function (req, res, next) { - console.warn('REST ', req.param('collection')); - }) - .get(RestResource.get) - .post(bodyParser.json(), RestResource.add) - .put(bodyParser.json(), RestResource.edit) - .delete(RestResource.destroy); - - router.use(bodyParser.json()); - router.use(bodyParser.urlencoded({extended: false})); - router.use(config.apiBase + '/upload2', upload.fileHandler()); - - - - // default options, immediately start reading from the request stream and -// parsing - router.use(busboy({immediate: true})); -// ... - router.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 ... - } - }); - - - return router; -}; - -module.exports = cmsRest; +module.exports = RestResource; diff --git a/routes/server.coffee b/routes/server.coffee deleted file mode 100644 index 5beac85..0000000 --- a/routes/server.coffee +++ /dev/null @@ -1,170 +0,0 @@ -# Module dependencies. -application_root = __dirname -express = require("express") -path = require("path") -mongoose = require("mongoose") -app = express() -# Add your coffee-script here -$rest = - endpoint: "http://localhost:9191/api" - create: (model, data) -> - @_send 'POST', model, data - read: (model) -> - @_send 'GET', model - update: (model, data) -> - @_send 'PUT', model, data - destroy: (model, data) -> - @_send 'DELETE', model, data - _send: (type, model, data) -> - url = @endpoint + "/" + model - url += '/' + data?.id if data?.id - - $.ajax - url: url - type: type - dataType: "json" - data: data - - -### -$ -> - - $rest.read('posts').then((data)-> - console.log(data) - ).fail((error)-> - console.error error - ) - - $rest.create('posts', name: 'test').then((data)-> - console.log(data) - ).fail((error)-> - console.error error - ) - - $rest.update('posts', id: 1, name: 'updated').then((data)-> - console.log(data) - ).fail((error)-> - console.error error - ) -### - -# Configure server -app.configure -> - - #parses request body and populates request.body - app.use express.bodyParser() - - #checks request.body for HTTP method overrides - app.use express.methodOverride() - - #perform route lookup based on URL and HTTP method - app.use app.router - - #Where to serve static content - app.use express.static(path.join(application_root, "../dist")) - - #Show all errors in development - app.use express.errorHandler( - dumpExceptions: true - showStack: true - ) - return - - -#Connect to database -mongoose.connect "mongodb://localhost/learning-yeoman" - -#Schemas -Post = new mongoose.Schema( - title: String - slug: String - body: String - image: String - published: Boolean - tags: Array - created: Date - modified: Date -) - -#Models -PostModel = mongoose.model("Post", Post) - -#Routes -# Routes -app.get "/api", (request, response) -> - response.send "API is running" - return - - -#Get a list -app.get "/api/posts", (request, response) -> - PostModel.find (err, data) -> - unless err - response.send data - else - console.log err - - - -#Insert a new -app.post "/api/posts", (request, response) -> - model = new PostModel( - title: request.body.title - slug: request.body.slug - body: request.body.body - image: request.body.image - published: request.body.published - tags: request.body.tags - created: new Date() - modified: new Date() - ) - model.save (err) -> - unless err - console.log "Created" - else - console.log err - - response.send model - - -#Get a single by id -app.get "/api/posts/:id", (request, response) -> - PostModel.findById request.params.id, (err, model) -> - unless err - response.send model - else - console.log err - -#Update -app.put "/api/posts/:id", (request, response) -> - console.log "Updating post " + request.body.title - PostModel.findById request.params.id, (err, model) -> - model.title = request.body.title - model.save (err) -> - unless err - console.log "model updated" - else - console.log err - response.send model - - return - - -#Delete -app.delete "/api/posts/:id", (request, response) -> - console.log "Deleting post with id: " + request.params.id - PostModel.findById request.params.id, (err, model) -> - model.remove (err) -> - unless err - console.log "model removed" - response.send "" - else - console.log err - return - - -#Start server -port = 9191 -app.listen port, -> - console.log "Express server listening on port %d in %s mode", port, app.settings.env - return diff --git a/routes/smartpass.js b/routes/smartpass.js deleted file mode 100644 index 3014741..0000000 --- a/routes/smartpass.js +++ /dev/null @@ -1,387 +0,0 @@ -/** - * @file smartpass.js - * @comment - * - * SmartPass API Module - */ - - -/** - * Configuration Object to hold - */ -var config = { - version: 'v1', - security : { - salt : 'a58e325c6df628d07a18b673a3420986' - }, - db : { - username : 'amadmin', - password : 'fred', - host : 'localhost', - port : 27017 - } -}; - -// Push options -var options = { - gateway: 'gateway.sandbox.push.apple.com', - cert: 'pusherCert.pem', - key: 'pushKey.pem', - passphrase: 'fred', - port: 2195, - enhanced: true, - cacheLength: 100 -}; - - -// Express server -var express = require('express'); - -// Express instance -var app = express(); - -//Configure express -app.configure(function() { - app.use(express.logger('dev')); - app.use("jsonp callback", true); - app.use(express.bodyParser({ - keepExtensions : true, - uploadDir : './temp' - })); - - // error logger - app.use(function(err, req, res, next) { - console.error(err.stack); - res.send(500, 'Something broke!'); - }); - - // simple logger - app.use(function(req, res, next) { - console.log('%s %s', req.method, req.url); - next(); - }); - -}); - - - -//Test device tokens -var deviceTokens = [ - '54563ea0fa550571c6ea228880c8c2c1e65914aa67489c38592838b8bfafba2a', - 'd46ba7d730f8536209e589a3abe205b055d66d8a52642fd566ee454d0363d3f3' -]; - - - -//API Endpoint -app.get('/smartpass', function(req, res){ - var body = 'Hello World'; - res.setHeader('Content-Type', 'text/plain'); - res.setHeader('Content-Length', body.length); - res.end(body); -}); - - - -//API Version Endpoint - http://localhost:3535/smartpass/v1 -app.get('/smartpass/'+config.version, function(req, res) { - res.json({message: 'AppMatrix Engine Apple Passbook API Server v1'}); -}); - - - -//Register Pass endpoint -app.post('/smartpass/'+config.version+'/devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier/:serialNumber', function(req, res) { - res.json({message: 'AppMatrix Engine Apple Passbook API Server v1'}); -}); - - - -//Post Logging endpoint -app.post('/smartpass/'+config.version+'/log', function(req, res) { - console.log(req.body); - res.json({message: 'AppMatrix Engine Apple Passbook API Server v1'}); -}); - - -//Get Logging endpoint - - - - -//Unregister Pass -app.delete('/smartpass/'+config.version+'/devices/:deviceLibraryIdentifier/:passTypeIdentifier/:serialNumber', function(req, res) { - res.json({message: 'AppMatrix Engine Apple Passbook API Server v1'}); -}); - - - -//Get devices - - - -//Register device -app.get('/smartpass/'+config.version+'/register/:token', function(req, res){ - - console.log('Register device ' + req.param('token')); -}); - - - -//Get serial numbers -app.get('/smartpass/'+config.version+'/devices/:deviceLibraryIdentifier/registrations/:passTypeIdentifier', function(req, res){ - - console.log('Push to device ' + req.param('token')); -}); - - - - -//Get latest version of pass -app.get('/smartpass/'+config.version+'/passes/:passTypeIdentifier/:serialNumber', function(req, res){ - - console.log('Push to device ' + req.param('token')); -}); - - - - -//Send push to device -app.get('/smartpass/'+config.version+'/push/:token', function(req, res){ - console.log('Push to device ' + req.param('token')); -}); - - - - -//Export to public api -exports.smartpass = { - app : app, - express : express, - init : function(port) { - app.listen(port); - console.log('SmartPass Server Listening on port ' + port); - } -}; - - - - - -/** - * smartpass Resource - * @author Jonnie Spratley, AppMatrix - * @created 10/23/12 - * - * Resource - This is the resource object that contains all of the REST api methods for a full CRUD on a mongo log document. - * - * REST METHODS: - * - * HTTP METHOD URL - * ======|==============|============================================== - * GET findAll http://localhost:3000/logs - * GET findById http://localhost:3000/logs/:id - * POST add http://localhost:3000/logs - * PUT update http://localhost:3000/logs/:id - * DELETE destroy http://localhost:3000/logs/:id - * - * //Resource usage - * var logs = require('./routes/logs'); - * app.get('/logs', logs.Resource.findAll); - * app.post('/logs', logs.Resource.add); - * app.put('/logs/:id', logs.Resource.update); - * app.get('/logs/:id', logs.Resource.findById); - * app.post('/logs/:id', logs.Resource.destroy); - */ -var Resource = { - host : 'localhost', - port : 27017, - /** - * I enable logging or not. - */ - debug : true, - /** - * I am the interal logger. - */ - log : function(obj) { - if (Resource.debug) { - console.log(obj); - } - }, - /** - * I am the name of the database. - */ - databaseName : 'logs_db', - /** - * I am the name of this collection. - */ - name : 'logs', - /** - * I am the example schema for this resources. - */ - schema : [{ - id : '', - title : '', - body : '', - page : '', - controller : '', - action : '', - created : '', - modified : '', - appid : '', - user_id : '', - log : '', - ip : '', - account_id : '', - application_id : '', - }], - /** - * I populate the document db with the schema. - */ - populateDb : function() { - db.collection(Resource.name, function(err, collection) { - collection.insert(Resource.schema, { - safe : true - }, function(err, result) { - Resource.log(result); - }); - }); - }, - /** - * I find all of the records - * @param {Object} req - * @param {Object} res - */ - findAll : function(req, res) { - db.collection(Resource.name, function(err, collection) { - collection.find().toArray(function(err, items) { - Resource.log(Resource.name + ':findAll - ' + JSON.stringify(items)); - res.send(items); - }); - }); - }, - /** - * I find one of the records by id. - * @param {Object} req - * @param {Object} res - */ - findById : function(req, res) { - - var id = req.params.id; - - Resource.log(Resource.name + ':findById - ' + id); - - db.collection(Resource.name, function(err, collection) { - collection.findOne({ - '_id' : new BSON.ObjectID(id) - }, function(err, item) { - res.send(item); - }); - }); - }, - /** - * I add a record to the collection - * @param {Object} req - * @param {Object} res - */ - add : function(req, res) { - var data = req.body; - - Resource.log(Resource.name + ':add - ' + JSON.stringify(data)); - - db.collection(Resource.name, function(err, collection) { - collection.insert(data, { - safe : true - }, function(err, result) { - if (err) { - res.send({ - 'error' : 'An error has occurred' - }); - } else { - Resource.log('Success: ' + JSON.stringify(result[0])); - res.send(result[0]); - } - }); - }); - }, - /** - * I update a record in the collection - * @param {Object} req - * @param {Object} res - */ - update : function(req, res) { - var id = req.params.id; - var data = req.body; - Resource.log(Resource.name + ':destroy -' + id + ' - ' + JSON.stringify(data)); - db.collection(Resource.name, function(err, collection) { - collection.update({ - '_id' : new BSON.ObjectID(id) - }, data, { - safe : true - }, function(err, result) { - if (err) { - res.send({ - 'error' : 'An error has occurred' - }); - console.log('Error updating ' + Resource.name + ': ' + err); - } else { - console.log('' + result + 'document(s) updated'); - - res.send(data); - } - }); - }); - }, - /** - * I delete a record in the collection. - * @param {Object} req - * @param {Object} res - */ - destroy : function(req, res) { - var id = req.params.id; - Resource.log(Resource.name + ':destroy -' + id); - db.collection(Resource.name, function(err, collection) { - collection.remove({ - '_id' : new BSON.ObjectID(id) - }, { - safe : true - }, function(err, result) { - if (err) { - res.send({ - 'error' : 'An error has occurred' - }); - Resource.log('Error updating ' + Resource.name + ': ' + err); - } else { - res.send(req.body); - } - }); - }); - } -}; - -var mongo = require('mongodb'), Server = mongo.Server, Db = mongo.Db, BSON = mongo.BSONPure; -var server = new Server(Resource.host, Resource.port, { - auto_reconnect : true, - safe : false -}); -var db = new Db(Resource.databaseName, server); - -/** - * Open the database and check for collection, if none - * then create it with the schema. - */ -db.open(function(err, db) { - if (!err) { - Resource.log('Connected to ' + Resource.databaseName); - db.collection(Resource.name, { - safe : true - }, function(err, collection) { - if (err) { - Resource.log('The collection doesnt exist. creating it with sample data...'); - Resource.populateDb(); - } - }); - } -}); - - diff --git a/routes/socketserver.js b/routes/socketserver.js index 1294916..999b08b 100644 --- a/routes/socketserver.js +++ b/routes/socketserver.js @@ -23,7 +23,8 @@ var sio = require( 'socket.io' ), q = require( 'q' ); var delay = function (fn, time) { var defer = q.defer(); setTimeout( function () { - defer.resolve( fn() ); + fn(); + defer.resolve(); }, time ); return defer.promise; } diff --git a/server.js b/server.js index 2dbc51d..1570592 100755 --- a/server.js +++ b/server.js @@ -4,21 +4,18 @@ */ var fs = require('fs'), util = require('util'), + http = require('http'), + express = require('express'), httpProxy = require('http-proxy'), - colors = require('colors'); - -colors.setTheme({ - silly: 'rainbow', - input: 'grey', - verbose: 'cyan', - prompt: 'grey', - info: 'green', - data: 'grey', - help: 'cyan', - warn: 'yellow', - debug: 'blue', - error: 'red' -}); + colors = require('colors'), + app = express(); + + + /** + * @TODO - Externalize configuration for server and proxy, mongodb + */ + var config = JSON.parse(fs.readFileSync('./config/config.json')); + /** * @TODO - HTTPS Key and Cert @@ -51,28 +48,17 @@ var options = { hostncmsOnly: true, router: {} }; -/** - * @TODO - Externalize configuration for server and proxy, mongodb - */ -var config = JSON.parse(fs.readFileSync('./config/config.json')); -var cmsAuth = require('./routes/cms-auth'); -var cmsRest = require('./routes/rest'); - -var rest = new cmsRest(config); -var auth = new cmsAuth(config, rest); -var webapp = auth.listen(config.port || process.env.PORT, function () { - console.log(String('Node.js REST server listening on port: ' + config.port).verbose); -}); -//Socket server -var socket = require('./routes/socketserver').SocketServer; -//Initialize socket server and rest server -socket.init(webapp); +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); +}); @@ -87,7 +73,7 @@ proxyServer = httpProxy.createServer(options, function (req, res, proxy) { host: '127.0.0.1', port: options.api.port }); - console.log('Routing request: API server'.warn); + util.log('Routing request: API server'.warn); } else if (req.url.match(/^\/1\//)) { @@ -95,7 +81,7 @@ proxyServer = httpProxy.createServer(options, function (req, res, proxy) { proxy.proxyRequest(req, res, { host: 'api.parse.com' }); - console.log('Routing request: Parse Server'.warn); + util.log('Routing request: Parse Server'.warn); } else { @@ -104,9 +90,10 @@ proxyServer = httpProxy.createServer(options, function (req, res, proxy) { host: '127.0.0.1', port: options.api.port }); - console.log('Routing request: App Server'.warn); + util.log('Routing request: App Server'.warn); } }); + //Start the proxy server -proxyServer.listen(options.port); +proxyServer.listen(config.proxy.port); diff --git a/test/routes/rest-spec.js b/test/routes/rest-spec.js index b66d98d..804d678 100644 --- a/test/routes/rest-spec.js +++ b/test/routes/rest-spec.js @@ -1,22 +1,22 @@ -var app, endpoint, expect, path, postData, request, rest; -request = require('supertest'); -path = require('path'); -fs = require('fs'); -expect = require('chai').expect; + +var request = require('supertest'); +var path = require('path'); +var fs = require('fs'); +var expect = require('chai').expect; +var express = require('express'); +var app = express(); var config = JSON.parse(fs.readFileSync(process.cwd() + '/config/config.json')); config.port = 9191 -var cmsAuth = require(process.cwd() + '/routes/cms-auth'); -var cmsRest = require(process.cwd() + '/routes/rest'); -var rest = new cmsRest(config); -var auth = new cmsAuth(config, rest); -auth.listen(config.port || process.env.PORT, function () { - console.log(String('Node.js REST server listening on port: ' + config.port).verbose); -}); -endpoint = 'http://localhost:8181/api/v2'; -postData = { +var cmsRoutes = require(process.cwd() + '/routes/cms-routes'); +cmsRoutes.mount(config, app); + +app.listen(9292); + +var endpoint = 'http://localhost:8181/api/v2'; +var postData = { "username": "nodetest" + Date.now(), "email": "nodetest@email.com", "password": "test", @@ -30,10 +30,12 @@ postData = { } }; + + describe('Testing: API Server', function () { it('POST - /api/v2/users/register - should return user on successful registation', function (done) { - request(auth) + request(app) .post('/api/v2/users/register') .send(postData) .expect("Content-Type", /json/) @@ -45,7 +47,7 @@ describe('Testing: API Server', function () { username: 'nodetest', password: 'test' }; - request(auth) + request(app) .post('/api/v2/users/login') .send(validUser) .expect("Content-Type", /json/) @@ -56,7 +58,7 @@ describe('Testing: API Server', function () { username: 'test1', password: 'wrongpassword' }; - request(auth) + request(app) .post('/api/v2/users/login') .send(invalidUser) .expect("Content-Type", /json/) From c6a6e1914dd6ccb783971b797379cfd9bb513b08 Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Mon, 8 Dec 2014 15:25:36 -0800 Subject: [PATCH 29/39] updated routes --- config/config.json | 2 +- package.json | 5 +- routes/cms-auth.js | 118 +++++++++++++++-- routes/cms-passport.js | 290 ++++++++++++++++++----------------------- routes/cms-proxy.js | 4 +- routes/cms-rest.js | 31 ++--- routes/cms-routes.js | 10 +- routes/cms-server.js | 4 +- routes/cms-sockets.js | 4 +- routes/cms-upload.js | 245 +++++++++++++++++----------------- routes/models/user.js | 127 ++++++++++++------ routes/rest.js | 63 --------- 12 files changed, 471 insertions(+), 432 deletions(-) diff --git a/config/config.json b/config/config.json index c4e1e82..44113dd 100644 --- a/config/config.json +++ b/config/config.json @@ -3,7 +3,7 @@ "port": 8181, "apiBase": "/api/v2", "version": "v2", - "security": {"salt": ""}, + "security": {"salt": "angular-cms"}, "mongodb": "localhost:27017/angular-cms", "db": { "name": "angular-cms", diff --git a/package.json b/package.json index a3e03b5..2edb42a 100755 --- a/package.json +++ b/package.json @@ -38,8 +38,7 @@ "emailjs": "~0.3.6", "express": "~4.0.0", "express-session": "^1.9.3", - "method-override": "~1.0.0", - "fs-extra": "^0.12.0", + "fs-extra": "^0.12.0", "http-proxy": "^1.3.0", "jps-ds": "~0.0.2", "jquery": "~2.1.0", @@ -48,7 +47,9 @@ "json-proxy": "^0.3.0", "logfmt": "~0.18.1", "markdown": "~0.5.0", + "method-override": "~1.0.0", "mongodb": "*", + "mongoose": "^3.8.20", "passport": "^0.2.1", "passport-facebook": "^1.0.3", "passport-google": "^0.3.0", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 963b606..e876872 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -1,14 +1,106 @@ -var passport = require('passport'), - express = require('express'), - BasicStrategy = require('passport-http').Strategy, - LocalStrategy = require('passport-local').Strategy, - GoogleStrategy = require('passport-google').Strategy, - path = require('path'), - q = require('q'), - flash = require('express-flash'), - DS = require('jps-ds').DS; - - - module.exports = function(config, app){ - console.warn('cms-auth'); +var bodyParser = require( 'body-parser' ), + mongoose = require( 'mongoose' ), + User = require( './models/user' ), + session = require( 'express-session' ), + crypto = require( 'crypto' ); + +module.exports = function (config, app) { + console.warn( 'cms-auth' ); + + mongoose.connect( config.mongodb ); + +//### hashPassword +//Hash password using basic sha1 hash. + var hashPassword = function (pass) { + var shasum = crypto.createHash( 'sha1' ); + shasum.update( config.security.salt + pass ); + + return shasum.digest( 'hex' ); }; + + var cmsAuth = { + /** + * //### login + //I handle trying to authorized a user with the v1 api server. + * @param req + * @param res + * @param next + */ + login: function (req, res, next) { + var query = {}; + + //TODO: Need to make this externalized. + if (req.body.username) { + query.username = req.body.username; + } + if (req.body.email) { + query.username = req.body.email; + } + + //TODO: Hashing on client side + query.password = hashPassword( req.body.password ); + + console.warn( 'Login Query: ' + JSON.stringify( query ) + ''.verbose ); + + User.findOne( query, function (err, data) { + if (err) { + res.jsonp( 400, err ); + } + if (data) { + res.jsonp( 200, data ); + } else { + res.jsonp( 404, {message: 'Wrong username/password!'} ); + } + } ); + + }, + /** + * Handle registering a new user + * @param req + * @param res + * @param next + */ + register: function (req, res, next) { + var data = req.body; + + //TODO: Need to make this externalized. + if (req.body.username) { + data.username = req.body.username; + } + if (req.body.email) { + data.username = req.body.email; + } + + //TODO: Hashing on client side + data.password = hashPassword( req.body.password ); + + console.log( String( "Register user" ).debug, data ); + + var user = new User( data ); + + //Try and find user + User.find( data, function (err, u) { + if (u) { + res.json( 400, {message: 'Username already exists!'} ); + } else { + user.save( function (err, ok) { + if (err) { + res.json( 400, {message: 'Problem registering!'} ); + } else { + res.json( 200, ok ); + } + } ); + } + + } ); + + }, + session: function (req, res, next) { + } + }; + + //Always users table + app.post( config.apiBase + '/users/login', bodyParser.json(), cmsAuth.login ); + app.post( config.apiBase + '/users/register', bodyParser.json(), cmsAuth.register ); + app.post( config.apiBase + '/users/session', bodyParser.json(), cmsAuth.session ); +}; diff --git a/routes/cms-passport.js b/routes/cms-passport.js index c88cf00..c40dd4d 100644 --- a/routes/cms-passport.js +++ b/routes/cms-passport.js @@ -1,163 +1,127 @@ -var passport = require('passport'), - BasicStrategy = require('passport-http').Strategy, - LocalStrategy = require('passport-local').Strategy, - GoogleStrategy = require('passport-google').Strategy, - log = require('npmlog'), - express = require('express'), - path = require('path'), - q = require('q'), - flash = require('express-flash'), - User = require('./models/user'), - cookieParser = require('cookie-parser'), - bodyParser = require('body-parser'), - session = require('express-session'); - - -module.exports = function(config, app){ - - - if (!app) { - throw new Error('Must provide express application!'); - } - - - // Simple route middleware to ensure user is authenticated. - // Use this route middleware on any resource that needs to be protected. If - // the request is authenticated (typically via a persistent login session), - // the request will proceed. Otherwise, the user will be redirected to the - // login page. - function ensureAuthenticated(req, res, next) { - if (req.isAuthenticated()) { - return next(); - } - res.redirect('/login'); - } - - // Passport session setup. - // To support persistent login sessions, Passport needs to be able to - // serialize users into and deserialize users out of the session. Typically, - // this will be as simple as storing the user ID when serializing, and finding - // the user by ID when deserializing. - - passport.serializeUser(function (user, done) { - done(null, user.id); - }); - - passport.deserializeUser(function (id, done) { - User.findById(id, function (err, user) { - done(err, user); - }); - }); - - - /* */ - - // Strategies in passport require a `verify` function, which accept - // credentials (in this case, a username and password), and invoke a callback - // with a user object. In the real world, this would query a database; - // however, in this example we are using a baked-in set of users. - passport.use(new LocalStrategy({ - usernameField: 'email', - passwordField: 'password' - }, 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); - }); - }); - } -)); - - /**/ - passport.use(new GoogleStrategy({ - returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' - }, - function (identifier, profile, done) { - console.warn('googleCallback', profile); - profile.openId = identifier; - 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({ - 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.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('/login', function (req, res) { - res.render('login', {user: req.user, message: 'Please login', status: 'warning'}); - }); - - - app.post('/login', - passport.authenticate('local', { - successRedirect: '/', - failureRedirect: '/login', - failureFlash: false - }) -); - -app.get('/auth/user', ensureAuthenticated, function (req, res) { - res.json(200, req.user); -}); - -app.get('/auth/logout', function (req, res) { - req.logout(); - res.redirect(options.apiBase); -}); - - -// Redirect the user to Google for authentication. When complete, Google -// will redirect the user back to the application at -// /auth/google/return -app.get('/auth/google', passport.authenticate('google')); - -// Google will redirect the user to this URL after authentication. Finish -// the process by verifying the assertion. If valid, the user will be -// logged in. Otherwise, authentication has failed. -app.get('/auth/google/return', -passport.authenticate('google', { - successRedirect: '/', - failureRedirect: '/login' -})); -app.get('/auth/logout', function (req, res) { - req.logout(); - res.redirect('/'); -}); - -} +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 ensureAuthenticated = function (req, res, next) { + if (req.isAuthenticated()) { + return next(); + } + res.redirect( '/login' ); +}; +module.exports = function (config, app) { + + if (!app) { + 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 ); + } ); + } ); + } + ) ); + + passport.use( new GoogleStrategy( { + returnURL: 'http://localhost:8181/auth/google/return', realm: 'http://localhost:8181/' + }, + function (identifier, profile, done) { + console.warn( 'googleCallback', profile ); + profile.openId = identifier; + 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( { + 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.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( '/login', function (req, res) { + res.render( 'login', {user: req.user, message: 'Please login', status: 'warning'} ); + } ); + + app.post( '/login', + passport.authenticate( 'local', { + successRedirect: '/', + failureRedirect: '/login', + failureFlash: false + } ) + ); + + app.get( '/auth/user', ensureAuthenticated, function (req, res) { + res.json( 200, req.user ); + } ); + + app.get( '/auth/logout', function (req, res) { + req.logout(); + res.redirect( options.apiBase ); + } ); + + app.get( '/auth/google', passport.authenticate( 'google' ) ); + app.get( '/auth/google/return', + passport.authenticate( 'google', { + successRedirect: '/', + failureRedirect: '/login' + } ) ); + +}; + + + diff --git a/routes/cms-proxy.js b/routes/cms-proxy.js index b7698cd..4053545 100644 --- a/routes/cms-proxy.js +++ b/routes/cms-proxy.js @@ -1,3 +1,3 @@ -module.exports = function(config, app){ - console.warn('cms-proxy', config, app); +module.exports = function (config, app) { + console.warn( 'cms-proxy', 'initialized' ); }; diff --git a/routes/cms-rest.js b/routes/cms-rest.js index cab2aa4..0fd127b 100644 --- a/routes/cms-rest.js +++ b/routes/cms-rest.js @@ -1,23 +1,20 @@ -var cookieParser = require('cookie-parser'), - bodyParser = require('body-parser'), - session = require('express-session'), - RestResource = require('./rest'); +var bodyParser = require( 'body-parser' ), + session = require( 'express-session' ), + RestResource = require( './rest' ); module.exports = function (config, app) { - "use strict"; + 'use strict'; - app.get(config.apiBase + '/plugins', RestResource.plugins); - app.get(config.apiBase + '/readme', RestResource.readme); - app.get(config.apiBase, RestResource.index); + app.get( config.apiBase + '/plugins', RestResource.plugins ); + app.get( config.apiBase + '/readme', RestResource.readme ); + app.get( config.apiBase, RestResource.index ); - //Always users table - app.post(config.apiBase + '/users/login', bodyParser.json(), RestResource.login); - app.post(config.apiBase + '/users/register', bodyParser.json(), RestResource.register); - app.post(config.apiBase + '/users/session', bodyParser.json(), RestResource.session); - //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); + //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 ); + + console.warn( 'cms-rest', 'initialized' ); }; diff --git a/routes/cms-routes.js b/routes/cms-routes.js index ac952c3..ed8b6f0 100644 --- a/routes/cms-routes.js +++ b/routes/cms-routes.js @@ -1 +1,9 @@ -module.exports.mount = function(config, 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); }; \ No newline at end of file +module.exports.mount = function (config, 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 ); +}; diff --git a/routes/cms-server.js b/routes/cms-server.js index b7698cd..d26cb07 100644 --- a/routes/cms-server.js +++ b/routes/cms-server.js @@ -1,3 +1,3 @@ -module.exports = function(config, app){ - console.warn('cms-proxy', config, app); +module.exports = function (config, app) { + console.warn( 'cms-server'); }; diff --git a/routes/cms-sockets.js b/routes/cms-sockets.js index b7698cd..6f5e779 100644 --- a/routes/cms-sockets.js +++ b/routes/cms-sockets.js @@ -1,3 +1,3 @@ -module.exports = function(config, app){ - console.warn('cms-proxy', config, app); +module.exports = function (config, app) { + console.warn( 'cms-sockts' ); }; diff --git a/routes/cms-upload.js b/routes/cms-upload.js index 0fd04ac..dcad55c 100644 --- a/routes/cms-upload.js +++ b/routes/cms-upload.js @@ -1,127 +1,122 @@ -var easyimage = require('easyimage'); -var upload = require('jquery-file-upload-middleware'); -var fs = require('fs-extra'); -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 ... - } - }); - - - - //### upload - //I handled processing a uploaded file on the v2 server. - var upload = function (req, res, next) { - var appid = 'public'; - - if (req.param('appid')) { - appid = String(req.param('appid')); - } - - console.log(util.inspect(req, {colors: true})); - - //Handle if dynamic filenames are enabled - var tmp_filename = req.files.file.name || 'tmp_name'; - var filename = tmp_filename; - var tmp_path = req.files.file.path; - var target_dir = config.uploadsDestDir + '/' + appid + '/'; - var target_path = config.uploadsDestDir + '/' + appid + '/' + filename; - var thumb_dir = config.uploadsDestDir + '/' + appid + '/thumbnail/'; - var thumb_path = config.uploadsDestDir + '/' + appid + '/thumbnail/' + filename; - - //Get the params for cropping an image - var x1 = req.body.x1, y1 = req.body.y1, x2 = req.body.x2, y2 = req.body.y2, height = req.body.height, width = req.body.width, filepath = target_path; - - if (!width) { - width = 150; - } - - //Log the vars - console.log(x1, x2, y1, y2, height, width, thumb_path); - - //Orignal image - console.log(String('Temp Path: ' + tmp_path).warn); - console.log(String('Target Dir: ' + target_dir).warn); - console.log(String('Target Path: ' + target_path).warn); - - //Thumbnail image - console.log(String('Original File: ' + filename).debug); - console.log(String('Original File Path: ' + target_path).debug); - console.log(String('Thumb Dir: ' + thumb_dir).debug); - console.log(String('Thumb Path: ' + thumb_path).debug); - - //Create the directory and move the file to that directory - fs.mkdir(target_dir, 0777, function (e) { - - //Rename the file - fs.rename(tmp_path, target_path, function (err) { - if (err) { - console.error('File Rename Error:', err); - } - - //Create the thumb directory - fs.mkdir(thumb_dir, 0777, function (e) { - - //Create the thumbnail from the default image - var imgOptions = { - src: target_path, - dst: thumb_path, - width: width, - height: height, - quality: 100, - x: x1, - y: y1 - }; - - //Resize the image - easyimg.resize(imgOptions, function (e) { - console.log('easyimg', imgOptions, e); - req.files.file.target_dir = target_dir; - req.files.file.target_path = target_path; - req.files.file.thumb_path = thumb_path; - req.files.file.thumb_dir = thumb_dir; - req.files.file.filename = filename; - - //build the response object - var json = { - status: true, - filename: filename, - targetDir: target_dir, - targetPath: target_path, - thumbDir: thumb_dir, - thumbPath: thumb_path, - msg: 'File Uploaded', - results: req.files, - appid: appid - }; - - //Output the results - res.send(json); - }); - }); - }); - }); - }; - - app.post(config.apiBase + '/upload', upload); - app.get(config.apiBase + '/upload', function (req, res, next) { - res.send({message: 'Upload a file with a POST.'}); - }); +var easyimage = require( 'easyimage' ); +var upload = require( 'jquery-file-upload-middleware' ); +var fs = require( 'fs-extra' ); +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 ... + } + } ); + + //### upload + //I handled processing a uploaded file on the v2 server. + var upload = function (req, res, next) { + var appid = 'public'; + + if (req.param( 'appid' )) { + appid = String( req.param( 'appid' ) ); + } + + console.log( util.inspect( req, {colors: true} ) ); + + //Handle if dynamic filenames are enabled + var tmp_filename = req.files.file.name || 'tmp_name'; + var filename = tmp_filename; + var tmp_path = req.files.file.path; + var target_dir = config.uploadsDestDir + '/' + appid + '/'; + var target_path = config.uploadsDestDir + '/' + appid + '/' + filename; + var thumb_dir = config.uploadsDestDir + '/' + appid + '/thumbnail/'; + var thumb_path = config.uploadsDestDir + '/' + appid + '/thumbnail/' + filename; + + //Get the params for cropping an image + var x1 = req.body.x1, y1 = req.body.y1, x2 = req.body.x2, y2 = req.body.y2, height = req.body.height, width = req.body.width, filepath = target_path; + + if (!width) { + width = 150; + } + + //Log the vars + console.log( x1, x2, y1, y2, height, width, thumb_path ); + + //Orignal image + console.log( String( 'Temp Path: ' + tmp_path ).warn ); + console.log( String( 'Target Dir: ' + target_dir ).warn ); + console.log( String( 'Target Path: ' + target_path ).warn ); + + //Thumbnail image + console.log( String( 'Original File: ' + filename ).debug ); + console.log( String( 'Original File Path: ' + target_path ).debug ); + console.log( String( 'Thumb Dir: ' + thumb_dir ).debug ); + console.log( String( 'Thumb Path: ' + thumb_path ).debug ); + + //Create the directory and move the file to that directory + fs.mkdir( target_dir, 0777, function (e) { + + //Rename the file + fs.rename( tmp_path, target_path, function (err) { + if (err) { + console.error( 'File Rename Error:', err ); + } + + //Create the thumb directory + fs.mkdir( thumb_dir, 0777, function (e) { + + //Create the thumbnail from the default image + var imgOptions = { + src: target_path, + dst: thumb_path, + width: width, + height: height, + quality: 100, + x: x1, + y: y1 + }; + + //Resize the image + easyimg.resize( imgOptions, function (e) { + console.log( 'easyimg', imgOptions, e ); + req.files.file.target_dir = target_dir; + req.files.file.target_path = target_path; + req.files.file.thumb_path = thumb_path; + req.files.file.thumb_dir = thumb_dir; + req.files.file.filename = filename; + + //build the response object + var json = { + status: true, + filename: filename, + targetDir: target_dir, + targetPath: target_path, + thumbDir: thumb_dir, + thumbPath: thumb_path, + msg: 'File Uploaded', + results: req.files, + appid: appid + }; + + //Output the results + res.send( json ); + } ); + } ); + } ); + } ); + }; + + app.post( config.apiBase + '/upload', upload ); + app.get( config.apiBase + '/upload', function (req, res, next) { + res.send( {message: 'Upload a file with a POST.'} ); + } ); }; diff --git a/routes/models/user.js b/routes/models/user.js index b95ac34..be18d5b 100644 --- a/routes/models/user.js +++ b/routes/models/user.js @@ -1,42 +1,87 @@ +// app/models/user.js +// load the things we need +var mongoose = require( 'mongoose' ); +var bcrypt = require( 'bcrypt-nodejs' ); -var User = function () {}; - -User.findOrCreate = function (profile, fn) { - console.warn('findOrCreate', profile); - User.findByEmail(profile.emails[0], function (err, user) { - fn(user); - }); -}; -User.findById = function (id, fn) { - var idx = id - 1; - console.warn('findById', id); - if (users[idx]) { - fn(null, users[idx]); - } else { - fn(new Error('User ' + id + ' does not exist')); - } -}; -User.findByUsername = function (username, fn) { - var defer = q.defer(); - console.warn('findByUsername', username); - for (var i = 0, len = users.length; i < len; i++) { - var user = users[i]; - if (user.username === username) { - defer.resolve(user); - } else { - console.warn('user not found', username); - } - } - return defer.promise; -}; -User.findByEmail = function (email, fn) { - console.warn('findByEmail', email); - for (var i = 0, len = users.length; i < len; i++) { - var user = users[i]; - if (user.email === email) { - return fn(null, user); - } - } - return fn(null, null); -}; -module.exports = User; +// define the schema for our user model +var UserSchema = mongoose.Schema( { + id: String, + provider: String, + displayName: String, + name: Object, + emails: Array, + photos: Array, + username: String, + email: String, + password: String, + active: Boolean, + meta: Object, + token: String, + created_at: Date, + updated_at: Date, + local: { + email: String, + password: String, + }, + facebook: { + id: String, + token: String, + email: String, + name: String + }, + twitter: { + id: String, + token: String, + displayName: String, + username: String + }, + google: { + id: String, + token: String, + email: String, + name: String + } + +} ); + +// methods ====================== +// generating a hash +UserSchema.method( 'generateHash', function (password) { + return bcrypt.hashSync( password, bcrypt.genSaltSync( 8 ), null ); +}); + +// checking if password is valid +UserSchema.method( 'validPassword', function (password) { + return bcrypt.compareSync( password, this.password ); +}); + +UserSchema.method( 'findOrCreate', function (profile, fn) { + console.warn( 'findOrCreate', profile ); + UserSchema.findByEmail( profile.emails[0], function (err, user) { + fn( user ); + } ); +}); + +UserSchema.method( 'findByUsername', function (username, fn) { + console.warn( 'findByUsername', username ); + this.find( {username: username}, function (err, data) { + if (err) { + fn( false, err ); + } + fn( data ); + } ); +} ); + +UserSchema.method( 'findByEmail', function (email, fn) { + console.warn( 'findByEmail', email ); + for (var i = 0, len = users.length; i < len; i++) { + var user = users[i]; + if (user.email === email) { + return fn( null, user ); + } + } + return fn( null, null ); +} ); + +// create the model for users and expose it to our app +module.exports = mongoose.model( 'User', UserSchema ); \ No newline at end of file diff --git a/routes/rest.js b/routes/rest.js index 50043f9..62820ac 100755 --- a/routes/rest.js +++ b/routes/rest.js @@ -192,70 +192,7 @@ var RestResource = { message: 'REST API Server ' + RestResource.useversion }); }, - /** - * //### login - //I handle trying to authorized a user with the v1 api server. - * @param req - * @param res - * @param next - */ - login: function (req, res, next) { - var query = {}; - //TODO: Need to make this externalized. - if (req.body.username) { - query.username = req.body.username; - } - if (req.body.email) { - query.username = req.body.email; - } - - //TODO: Hashing on client side - query.password = hashPassword(req.body.password, query.username); - - console.warn('Login Query: ' + JSON.stringify(query) + ''.verbose); - - _ds.findOne('users', query).then(function (data) { - if (data) { - res.jsonp(200, data); - } else { - res.jsonp(404, {message: 'Wrong username/password!'}); - } - - }, function (err) { - res.jsonp(400, err); - }); - - }, - /** - * Handle registering a new user - * @param req - * @param res - * @param next - */ - register: function (req, res, next) { - var data = req.body; - - //TODO: Need to make this externalized. - if (req.body.username) { - data.username = req.body.username; - } - if (req.body.email) { - data.username = req.body.email; - } - - //TODO: Hashing on client side - data.password = hashPassword(req.body.password, data.username); - - _ds.create('users', data).then(function (user) { - res.json(201, user); - }, function (err) { - res.json(400, err); - }); - // console.log(String("Register user").debug, query); - }, - session: function (req, res, next) { - }, //### get From dd7f013592e75366888d92e59044b4954e0fbfc7 Mon Sep 17 00:00:00 2001 From: Jonathan Spratley Date: Mon, 8 Dec 2014 15:33:00 -0800 Subject: [PATCH 30/39] fixed regiser/login --- app/index.html | 2 +- config/config.json | 2 +- routes/cms-auth.js | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/index.html b/app/index.html index a9d41e4..1d38fd7 100755 --- a/app/index.html +++ b/app/index.html @@ -91,7 +91,7 @@ ga('send', 'pageview'); - + diff --git a/config/config.json b/config/config.json index 44113dd..ee1081f 100644 --- a/config/config.json +++ b/config/config.json @@ -4,7 +4,7 @@ "apiBase": "/api/v2", "version": "v2", "security": {"salt": "angular-cms"}, - "mongodb": "localhost:27017/angular-cms", + "mongodb": "angularcms:angularcms@paulo.mongohq.com:10089/app19632340", "db": { "name": "angular-cms", "username": "amadmin", diff --git a/routes/cms-auth.js b/routes/cms-auth.js index e876872..b9856f2 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -80,18 +80,18 @@ module.exports = function (config, app) { //Try and find user User.find( data, function (err, u) { + console.log(err, u); if (u) { res.json( 400, {message: 'Username already exists!'} ); - } else { - user.save( function (err, ok) { - if (err) { - res.json( 400, {message: 'Problem registering!'} ); - } else { - res.json( 200, ok ); - } - } ); } + } ); + user.save( function (err, ok) { + if (err) { + res.json( 400, {message: 'Problem registering!'} ); + } else { + res.json( 200, ok ); + } } ); }, From 035124ece73f1ec60d7c368fcfcbdedab5a83492 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 17:25:59 -0800 Subject: [PATCH 31/39] updated specs login/register --- app/scripts/controllers/login.coffee | 5 ++- app/scripts/controllers/register.coffee | 8 ++-- app/scripts/controllers/users.coffee | 6 +-- app/views/users.html | 9 +++-- bower.json | 3 -- config/config.json | 2 +- routes/cms-auth.js | 52 +++++++++++++++---------- routes/cms-sockets.js | 10 ++++- routes/models/user.js | 3 +- routes/rest.js | 4 +- test/routes/rest-spec.js | 9 ++--- 11 files changed, 63 insertions(+), 48 deletions(-) diff --git a/app/scripts/controllers/login.coffee b/app/scripts/controllers/login.coffee index c8103eb..9708361 100644 --- a/app/scripts/controllers/login.coffee +++ b/app/scripts/controllers/login.coffee @@ -37,8 +37,9 @@ angular.module('angularCmsApp').controller 'LoginCtrl', ($scope, $rootScope, $co #Change location $rootScope.App.location.path('/dashboard') , - (error)-> - cmsNotify( '.login-message', 'danger', 'Error!', error.message, 2500) + (err)-> + console.error(err) + cmsNotify( '.login-message', 'danger', 'Error!', err.data.message, 2500) ) ### diff --git a/app/scripts/controllers/register.coffee b/app/scripts/controllers/register.coffee index 83b7dd9..327e38b 100644 --- a/app/scripts/controllers/register.coffee +++ b/app/scripts/controllers/register.coffee @@ -32,7 +32,7 @@ angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $location, $ #Welcome the user cmsNotify( '.message', 'info', 'Registered!', "You have registered as #{data.user.email}") - + #Set user session session = user: data.user @@ -45,7 +45,7 @@ angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $location, $ $location.path('/dashboard') ) , - (error) -> - $log.error(error) - cmsNotify( '.message', 'danger', 'Error!', error.message, 4000) + (err) -> + $log.error(err) + cmsNotify( '.message', 'danger', 'Error!', err.data.message, 4000) ) diff --git a/app/scripts/controllers/users.coffee b/app/scripts/controllers/users.coffee index df2984b..a8a9f59 100644 --- a/app/scripts/controllers/users.coffee +++ b/app/scripts/controllers/users.coffee @@ -11,8 +11,8 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> email: null password: null role: 'member' - created: new Date() - modified: new Date() + created_at: new Date() + updated_at: new Date() metadata: avatar: '' name: null @@ -44,7 +44,6 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> #Delete user $scope.deleteUser = (index, user) -> ask = confirm "Delete #{user.email}?" - if ask DataService.destroy('users', user).then((res) -> $scope.users.pop(index) @@ -53,7 +52,6 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> #Add user to database $scope.addUser = (user) -> - user.created_at = new Date() user.updated_at = new Date() DataService.save('users', user).then((data) -> $scope.getUsers() diff --git a/app/views/users.html b/app/views/users.html index efed6e2..c61b92b 100755 --- a/app/views/users.html +++ b/app/views/users.html @@ -14,10 +14,10 @@

Users + Username E-mail - Active - Created + Last Updated Actions @@ -26,13 +26,14 @@

Users + {{ user.username }} {{user.email}} - {{ user.username }} + {{group}} {{user.active}} - {{user.created | date:'medium'}} + {{user.updated_at | date:'medium'}}
" + msg + "
" - $(".messages").empty() - $(".messages").append html - return - - WebSocketClient = (options) -> - _ws = undefined - _ws = new WebSocket(options.endpoint, options.protocol) - _ws.onmessage = (e) -> - notify "info", e.data - console.log e.data - return - - _ws.onerror = (e) -> - notify "danger", "There was an error" - console.log e - return - - _ws.onclose = (e) -> - notify "danger", "Socket is now closed" - console.log e - return - - _ws.onopen = (e) -> - notify "success", "Socket is now open" - _ws.send "update" - return - - instance: _ws - close: -> - _ws.close() - - send: (obj) -> - try - _ws.send obj - catch err - throw err - return - - s = "" - - #Document - $(document).ready -> - ws = null - - #Open - $(".btn-connect").click (e) -> - options = - endpoint: $("#ws-endpoint").val() - protocol: $("#ws-protocol").val() - - ws = new WebSocketClient(options) - console.log ws - log "Connecting to socket" - return - - - #Close - $(".btn-disconnect").click (e) -> - ws.close() - log "Disconnecting from socket" - return - - - #Send - $(".btn-message").click (e) -> - msg = $("#ws-msg").val() - log "Sending: " + msg - ws.send msg - return - - return - diff --git a/karma.conf.js b/karma.conf.js index 728057e..ee0b2d5 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -23,6 +23,7 @@ module.exports = function (config) { 'app/bower_components/angular-route/angular-route.js', 'app/bower_components/angular-ui-utils/ui-utils.js', 'app/bower_components/angular-strap/dist/angular-strap.min.js', + 'app/bower_components/angular-*/dist/angular-*.js', //Libs 'app/scripts/libs/parse-1.2.17.min.js', From 6aff011a364e344494c490debbba8d046319d8c4 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 17:43:08 -0800 Subject: [PATCH 34/39] Using heroku db now --- app/scripts/controllers/users.coffee | 1 + app/views/users.html | 2 +- config/config.json | 2 +- routes/rest.js | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/users.coffee b/app/scripts/controllers/users.coffee index a8a9f59..df8166d 100644 --- a/app/scripts/controllers/users.coffee +++ b/app/scripts/controllers/users.coffee @@ -52,6 +52,7 @@ angular.module('angularCmsApp').controller('UsersCtrl', ($scope, DataService) -> #Add user to database $scope.addUser = (user) -> + delete user.password if user.password user.updated_at = new Date() DataService.save('users', user).then((data) -> $scope.getUsers() diff --git a/app/views/users.html b/app/views/users.html index c61b92b..d429f58 100755 --- a/app/views/users.html +++ b/app/views/users.html @@ -88,7 +88,7 @@
- +

diff --git a/config/config.json b/config/config.json index e3f5c29..ee1081f 100644 --- a/config/config.json +++ b/config/config.json @@ -4,7 +4,7 @@ "apiBase": "/api/v2", "version": "v2", "security": {"salt": "angular-cms"}, - "mongodb": "localhost/angular-cms", + "mongodb": "angularcms:angularcms@paulo.mongohq.com:10089/app19632340", "db": { "name": "angular-cms", "username": "amadmin", diff --git a/routes/rest.js b/routes/rest.js index a6b68b3..44e3fd4 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, From c620d9cd07b3236439d8090d90814499ace72c7e Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 18:29:36 -0800 Subject: [PATCH 35/39] Added gulp + routes --- Gruntfile.js | 5 +- app/scripts/services/cmsauthservice.coffee | 10 +- gulpfile.js | 13 ++- package.json | 1 + protractor.conf.js | 4 +- routes/cms-auth.js | 28 +++-- test/protractor/App.js | 54 --------- test/protractor/app-spec.coffee | 110 ------------------ test/protractor/{ => pages}/app-page.coffee | 0 test/protractor/{ => pages}/login-page.coffee | 0 .../{ => pages}/register-page.coffee | 0 test/protractor/{ => pages}/users-page.coffee | 0 test/protractor/spec/app-spec.coffee | 15 +++ test/protractor/spec/login-spec.coffee | 24 ++++ test/protractor/spec/register-spec.coffee | 16 +++ test/protractor/spec/users-spec.coffee | 0 test/routes/rest-spec.js | 6 +- 17 files changed, 100 insertions(+), 186 deletions(-) delete mode 100644 test/protractor/App.js delete mode 100644 test/protractor/app-spec.coffee rename test/protractor/{ => pages}/app-page.coffee (100%) rename test/protractor/{ => pages}/login-page.coffee (100%) rename test/protractor/{ => pages}/register-page.coffee (100%) rename test/protractor/{ => pages}/users-page.coffee (100%) create mode 100644 test/protractor/spec/app-spec.coffee create mode 100644 test/protractor/spec/login-spec.coffee create mode 100644 test/protractor/spec/register-spec.coffee create mode 100644 test/protractor/spec/users-spec.coffee diff --git a/Gruntfile.js b/Gruntfile.js index 27a6269..70bff42 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -57,10 +57,7 @@ module.exports = function (grunt) { files: ['test/spec/{,**/}*.{coffee,litcoffee,coffee.md}'], tasks: ['coffee:test', 'newer:coffee:test', 'karma:unit'] }, - coffeeProtractorTest: { - files: ['test/protractor/{,**/}*.{coffee,litcoffee,coffee.md}'], - tasks: ['coffee:test', 'newer:coffee:test', 'protractor'] - }, + compass: { files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], tasks: ['compass:server', 'autoprefixer'] diff --git a/app/scripts/services/cmsauthservice.coffee b/app/scripts/services/cmsauthservice.coffee index 954d182..29d2851 100644 --- a/app/scripts/services/cmsauthservice.coffee +++ b/app/scripts/services/cmsauthservice.coffee @@ -21,13 +21,19 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo authorize - I handle authorizing a user. ### authorize: (user) -> - return $http.post( @endpoint+"/users/login", user ) + return $http.post( @endpoint+"/login", user ) + + ###* + session - I handle getting a session. + ### + session: () -> + return $http.get( @endpoint+"/session" ) ###* register - I handle register a user. ### register: (user) -> - return $http.post( @endpoint+"/users/register", user ) + return $http.post( @endpoint+"/register", user ) ###* Logout method to clear the session. diff --git a/gulpfile.js b/gulpfile.js index eea6692..556643e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,14 +5,21 @@ coffee = require( 'gulp-coffee' ); uglify = require( 'gulp-uglify' ); gulp.task( 'js', function () { - return gulp + gulp .src( './app/scripts/**/*.coffee' ) .pipe( coffee() ) .pipe( uglify() ) .pipe( gulp.dest( './.tmp/scripts' ) ); } ); +gulp.task( 'js:test', function () { + gulp + .src( './test/**/*.coffee' ) + .pipe( coffee() ) + .pipe( uglify() ) + .pipe( gulp.dest( './.tmp' ) ); +} ); gulp.task( 'watch', function () { - return gulp - .watch( './app/scripts/**/*.coffee', ['js'] ); + gulp.watch( './app/scripts/**/*.coffee', ['js'] ); + gulp.watch( './test/**/*.coffee', ['js:test'] ) } ); diff --git a/package.json b/package.json index 2edb42a..2686c2b 100755 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "grunt-svgmin": "~0.2.0", "grunt-usemin": "~2.0.2", "gulp-ngmin": "^0.3.0", + "gulp-uglify": "^1.0.2", "jasmine-core": "^2.1.2", "jasmine-node": "~1.11.0", "jasmine-reporters": "^1.0.1", diff --git a/protractor.conf.js b/protractor.conf.js index 0872e12..25dee63 100644 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -30,8 +30,8 @@ exports.config = { // Spec patterns are relative to the current working directly when // protractor is called. specs: [ - '.tmp/protractor/*-spec.js', - 'test/protractor/*-spec.js' + '.tmp/protractor/**/*-spec.js', + 'test/protractor/**/*-spec.js' ], // Options to be passed to Jasmine-node. diff --git a/routes/cms-auth.js b/routes/cms-auth.js index 183dc95..06ae36b 100644 --- a/routes/cms-auth.js +++ b/routes/cms-auth.js @@ -43,13 +43,18 @@ module.exports = function (config, app) { if (err) { res.jsonp( 400, err ); } - if (data && bcrypt.compareSync(req.body.password, data.password)) { - res.jsonp( 200, data ); - } else { - res.jsonp( 404, {message: 'Wrong username/password!'} ); + + try { + if (data && bcrypt.compareSync(req.body.password, data.password)) { + req.session.user = data; + res.jsonp( 200, data ); + } else { + res.jsonp( 404, {message: 'Wrong username/password!'} ); + } + } catch (error) { + res.jsonp( 404, {message: error} ); } } ); - }, /** * Handle registering a new user @@ -99,6 +104,12 @@ module.exports = function (config, app) { } ); }, session: function (req, res, next) { + var user = req.session; + if(req.session && req.session.user){ + user = req.session.user + } + console.warn(util.inspect(user, {colors: true})); + res.send({message: 'Your session', data: user}); } }; @@ -108,7 +119,8 @@ module.exports = function (config, app) { resave: true, saveUninitialized: true } ) ); - app.post( config.apiBase + '/users/login', bodyParser.json(), cmsAuth.login ); - app.post( config.apiBase + '/users/register', bodyParser.json(), cmsAuth.register ); - app.post( config.apiBase + '/users/session', bodyParser.json(), cmsAuth.session ); + app.get( config.apiBase + '/login', bodyParser.json(), cmsAuth.login ); + app.post( config.apiBase + '/login', bodyParser.json(), cmsAuth.login ); + app.post( config.apiBase + '/register', bodyParser.json(), cmsAuth.register ); + app.get( config.apiBase + '/session', bodyParser.json(), cmsAuth.session ); }; diff --git a/test/protractor/App.js b/test/protractor/App.js deleted file mode 100644 index 2233513..0000000 --- a/test/protractor/App.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * This is the protractor spec that will test the different areas of the application. - */ - -/** - * UsersPage - This page object controls actions on the /users page. - * @constructor - */ -var UsersPage = function () { - this.newUserBtn = element( by.buttonText( 'New User' ) ); - this.submitBtn = element( by.buttonText( 'Submit' ) ); - - this.inputs = { - email: element( protractor.By.model( 'user.email' ) ), - username: element( protractor.By.model( 'user.username' ) ), - password: element( protractor.By.model( 'user.password' ) ), - name: element( protractor.By.model( 'user.meta.name' ) ), - summary: element( protractor.By.model( 'user.meta.summary' ) ) - }; - - this.get = function () { - browser.get( 'http://localhost:9000/#/users' ); - }; - - this.setForm = function (email, username, password, name, summary) { - this.newUserBtn.click(); - browser.sleep( 500 ); - this.inputs.username.sendKeys( username ); - this.inputs.email.sendKeys( email ); - this.inputs.password.sendKeys( password ); - this.inputs.name.sendKeys( name ); - this.inputs.summary.sendKeys( summary ); - - this.submitBtn.click(); - browser.sleep( 1000 ); - }; - -}; - -describe( 'Angular-CMS', function () { - var usersPage = null; - - describe( 'Users Page:', function () { - beforeEach( function () { - usersPage = new UsersPage(); - usersPage.get(); - } ); - - it( 'should be able to create a new user', function () { - var username = 'protractor' + Date.now(); - usersPage.setForm( username + '@test.com', username, 'test', 'John Doe', 'This is an example user.' ); - } ); - } ); -} ); diff --git a/test/protractor/app-spec.coffee b/test/protractor/app-spec.coffee deleted file mode 100644 index 64340fa..0000000 --- a/test/protractor/app-spec.coffee +++ /dev/null @@ -1,110 +0,0 @@ -AppPage = require('./app-page') -UsersPage = require('./users-page') -LoginPage = require('./login-page') -RegisterPage = require('./register-page') - -App = null -usersPage = null -registerPage = null -loginPage = null - -###* -Protractor e2e Tests -### -describe "Angular-CMS App", -> - beforeEach -> - App = new AppPage() - App.get() - #Welome Story: the initial page - describe 'Index:', -> - it "should display the main index view as default", -> - expect(browser.getCurrentUrl()).toEqual '/' - - it 'should have a .navbar-brand on the page', -> - expect(j$.element('.navbar-brand', 'Site title').count()).toEqual 1 - - it 'should have a .login-btn element with a link to the login page', -> - expect(j$.element('a[href="#/login"]', 'the Login link').count()).toEqual 1 - - it 'should have a .media element for a feature', -> - browser.sleep 1 - expect(j$.element('.media').count()).toBeGreaterThan 1 - - it 'should have a jumbrotron element for feature title and body', -> - browser.sleep 1 - expect(j$.element('.jumbotron').count()).toEqual 1 - - - ###* - Register - The user registration implementation - ### - describe 'Register: ', -> - it 'should have email and password inputs with a button to submit the form', -> - registerPage = new RegisterPage() - registerPage.get() - expect(driver.getCurrentUrl()).toContain 'register' - expect(j$.element('form', 'Login form').count()).toEqual 1 - expect(j$.element('input[name="email"]', 'Email input').count()).toEqual 1 - expect(j$.element('input[name="username"]', 'Username input').count()).toEqual 1 - expect(j$.element('input[name="password"]', 'Password input').count()).toEqual 2 - expect(j$.element('button[type="submit"]', 'Submit button').count()).toEqual 1 - - ###* - Login - The user login implementation - ### - describe 'Login:', -> - - #Click the login button each time - beforeEach -> - loginPage = new LoginPage() - element('a[href="#/login"]', 'Login button').click() - - #Make sure we end up at the login page to enter our credentials - #Make sure there is a username and password input with button - it 'should have Username and password inputs with a button to submit the form', -> - expect(browser().location().path()).toEqual '/login' - expect(element('form', 'Login form').count()).toEqual 1 - expect(element('input[name="username"]', 'Username input').count()).toEqual 1 - expect(element('input[name="password"]', 'Password input').count()).toEqual 1 - expect(element('button[type="submit"]', 'Submit button').count()).toEqual 1 - - #Login to the page - loginPage.login() - - #Wait for the api call to go thru - sleep 1 - #We should end up at the dashboard page. - expect(browser().location().path()).toEqual '/dashboard' - - #The dashboard implementation - describe 'Dashboard: viewing the dashboard...', -> - beforeEach -> - loginPage = new LoginPage() - loginPage.login('test@gmail.com', 'test') - browser.sleep 1 - it 'should have a link to the profile page', -> - expect(j$.element('.widget', 'Widget Panel').count()).toEqual 2 - expect(j$.element('a[ng-href="#/profile"]', 'the Profile link').count()).toEqual 1 - expect(j$.element('.cms-sidebar-nav', 'Sidebar nav').count()).toEqual 1 - - describe "Users Page:", -> - beforeEach -> - usersPage = new UsersPage() - usersPage.get() - it "should be able to create a new user", -> - username = "protractor" + Date.now() - usersPage.setForm username + "@test.com", username, "test", "John Doe", "This is an example user." - -#The user registration implementation - - -#The user forgot password implementation - - -# The CRUD operations on DB implementation - - -# User table - - -#User form diff --git a/test/protractor/app-page.coffee b/test/protractor/pages/app-page.coffee similarity index 100% rename from test/protractor/app-page.coffee rename to test/protractor/pages/app-page.coffee diff --git a/test/protractor/login-page.coffee b/test/protractor/pages/login-page.coffee similarity index 100% rename from test/protractor/login-page.coffee rename to test/protractor/pages/login-page.coffee diff --git a/test/protractor/register-page.coffee b/test/protractor/pages/register-page.coffee similarity index 100% rename from test/protractor/register-page.coffee rename to test/protractor/pages/register-page.coffee diff --git a/test/protractor/users-page.coffee b/test/protractor/pages/users-page.coffee similarity index 100% rename from test/protractor/users-page.coffee rename to test/protractor/pages/users-page.coffee diff --git a/test/protractor/spec/app-spec.coffee b/test/protractor/spec/app-spec.coffee new file mode 100644 index 0000000..48c0234 --- /dev/null +++ b/test/protractor/spec/app-spec.coffee @@ -0,0 +1,15 @@ +AppPage = require('../pages/app-page') + + +###* +Protractor e2e Tests +### +App = new AppPage() +describe "Angular-CMS App", -> + beforeEach -> + App.get() + + #Welome Story: the initial page + describe 'Index:', -> + it "should display the main index view as default", -> + expect(browser.getLocationAbsUrl()).toEqual '/' diff --git a/test/protractor/spec/login-spec.coffee b/test/protractor/spec/login-spec.coffee new file mode 100644 index 0000000..fb20fc5 --- /dev/null +++ b/test/protractor/spec/login-spec.coffee @@ -0,0 +1,24 @@ +LoginPage = require('../pages/login-page') +loginPage = new LoginPage() +###* + Login - The user login implementation +### +describe 'Login:', -> + + #Click the login button each time + beforeEach -> + $('a[href="#/login"]').click() + + #Make sure we end up at the login page to enter our credentials + #Make sure there is a username and password input with button + it 'should have Username and password inputs with a button to submit the form', -> + expect(browser.getLocationAbsUrl()).toEqual '/login' + + #Login to the page + loginPage.login('test@email.com', 'test') + + #Wait for the api call to go thru + sleep 1 + + #We should end up at the dashboard page. + expect(browser.getLocationAbsUrl()).toEqual '/dashboard' diff --git a/test/protractor/spec/register-spec.coffee b/test/protractor/spec/register-spec.coffee new file mode 100644 index 0000000..f4a6692 --- /dev/null +++ b/test/protractor/spec/register-spec.coffee @@ -0,0 +1,16 @@ +RegisterPage = require('../pages/register-page') +j$ = require('../j$') + +###* +Register - The user registration implementation +### +describe 'Register: ', -> + it 'should have email and password inputs with a button to submit the form', -> + registerPage = new RegisterPage() + registerPage.get() + expect(browser.getCurrentUrl()).toContain 'register' + expect(j$.element('form', 'Login form').count()).toEqual 1 + expect(j$.element('input[name="email"]', 'Email input').count()).toEqual 1 + expect(j$.element('input[name="username"]', 'Username input').count()).toEqual 1 + expect(j$.element('input[name="password"]', 'Password input').count()).toEqual 2 + expect(j$.element('button[type="submit"]', 'Submit button').count()).toEqual 1 diff --git a/test/protractor/spec/users-spec.coffee b/test/protractor/spec/users-spec.coffee new file mode 100644 index 0000000..e69de29 diff --git a/test/routes/rest-spec.js b/test/routes/rest-spec.js index 5e617c0..5b2eba0 100644 --- a/test/routes/rest-spec.js +++ b/test/routes/rest-spec.js @@ -35,7 +35,7 @@ describe('Testing: API Server', function () { it('POST - /api/v2/users/register - should return user on successful registation', function (done) { request(app) - .post('/api/v2/users/register') + .post('/api/v2/register') .send(postData) .expect("Content-Type", /json/) .expect(201, done); @@ -47,7 +47,7 @@ describe('Testing: API Server', function () { password: 'test' }; request(app) - .post('/api/v2/users/login') + .post('/api/v2/login') .send(validUser) .expect("Content-Type", /json/) .expect(200, done); @@ -58,7 +58,7 @@ describe('Testing: API Server', function () { password: 'wrongpassword' }; request(app) - .post('/api/v2/users/login') + .post('/api/v2/login') .send(invalidUser) .expect("Content-Type", /json/) .expect(404, done); From 64f533beda496e4d8fb930a56d1f80cb1c1d0e93 Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Mon, 8 Dec 2014 21:44:45 -0800 Subject: [PATCH 36/39] updated specs --- Gruntfile.js | 26 +++++++--------- app/scripts/controllers/login.coffee | 2 +- app/styles/main.css | 2 +- app/views/login.html | 4 +-- app/views/register.html | 11 ++++--- gulpfile.js | 9 ++++-- routes/rest.js | 4 +-- test/protractor/j$.coffee | 2 +- test/protractor/pages/app-page.coffee | 7 +++-- test/protractor/pages/login-page.coffee | 18 ++++++----- test/protractor/pages/register-page.coffee | 35 ++++++++++++---------- test/protractor/spec/app-spec.coffee | 15 +++++----- test/protractor/spec/login-spec.coffee | 24 ++++----------- test/protractor/spec/register-spec.coffee | 15 ++++------ 14 files changed, 84 insertions(+), 90 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 70bff42..6991993 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,5 +1,5 @@ /* jshint camelcase:false */ -// Generated on 2013-12-06 using generator-angular 0.6.0-rc.2 +var fs = require('fs'); 'use strict'; // # Globbing @@ -7,7 +7,11 @@ // 'test/spec/{,*/}*.js' // use this if you want to recursively match all subfolders: // 'test/spec/**/*.js' - +/** +* @TODO - Externalize configuration for server and proxy, mongodb +*/ +var config = JSON.parse(fs.readFileSync(__dirname + '/config/config.json')); +var cmsRoutes = require(__dirname + '/routes/cms-routes'); var serverEndpoint = 'http://localhost:8181'; var proxyConfig = { proxy: { @@ -31,10 +35,7 @@ module.exports = function (grunt) { //Connect proxy to route requests to localhost:8181/api grunt.loadNpmTasks('grunt-connect-proxy'); require('json-proxy').initialize({}); - // Load grunt tasks automatically require('load-grunt-tasks')(grunt); - - // Time how long tasks take. Can help when optimizing build times require('time-grunt')(grunt); var GruntConfig = { @@ -57,7 +58,7 @@ module.exports = function (grunt) { files: ['test/spec/{,**/}*.{coffee,litcoffee,coffee.md}'], tasks: ['coffee:test', 'newer:coffee:test', 'karma:unit'] }, - + compass: { files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], tasks: ['compass:server', 'autoprefixer'] @@ -89,13 +90,7 @@ module.exports = function (grunt) { // Change this to '0.0.0.0' to access the server from outside. hostname: '127.0.0.1', livereload: 35729, - middleware: function (connect, options) { - return [ - require('json-proxy').initialize(proxyConfig), - mountFolder(connect, '.grunt'), - mountFolder(connect, '.tmp') - ]; - } + base: ['.tmp', '<%= yeoman.app %>'] }, livereload: { options: { @@ -103,8 +98,9 @@ module.exports = function (grunt) { base: ['.tmp', '<%= yeoman.app %>'], middleware: function (connect, options) { return [ - require('json-proxy').initialize(proxyConfig), - mountFolder(connect, '.tmp'), + require('json-proxy').initialize(proxyConfig), + mountFolder(connect, '.grunt'), + mountFolder(connect, '.tmp'), mountFolder(connect, 'app') ]; } diff --git a/app/scripts/controllers/login.coffee b/app/scripts/controllers/login.coffee index 9708361..331ae09 100644 --- a/app/scripts/controllers/login.coffee +++ b/app/scripts/controllers/login.coffee @@ -39,7 +39,7 @@ angular.module('angularCmsApp').controller 'LoginCtrl', ($scope, $rootScope, $co , (err)-> console.error(err) - cmsNotify( '.login-message', 'danger', 'Error!', err.data.message, 2500) + cmsNotify( '.login-message', 'danger', 'Error!', err.data.message) ) ### diff --git a/app/styles/main.css b/app/styles/main.css index 1f29dee..68e1fc2 100755 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -2,7 +2,7 @@ http://127.0.0.1:9000/styles/main.css http://localhost:9000/styles/main.css */ -@import url('https://cdn.rawgit.com/McNull/angular-form-gen/v0.0.1/dist/angular-form-gen.min.css'); +@import url('../bower_components/angular-form-gen/dist/angular-form-gen.min.css'); .navbar-avatar { height: 20px; diff --git a/app/views/login.html b/app/views/login.html index b9df191..a5fc89b 100755 --- a/app/views/login.html +++ b/app/views/login.html @@ -10,11 +10,11 @@
-
-

diff --git a/app/views/register.html b/app/views/register.html index ad7e0bf..6bc193c 100755 --- a/app/views/register.html +++ b/app/views/register.html @@ -8,21 +8,21 @@

- +
- +
- +
-
@@ -34,6 +34,5 @@
Back to Login -
diff --git a/gulpfile.js b/gulpfile.js index 556643e..e29d1eb 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,15 +7,18 @@ uglify = require( 'gulp-uglify' ); gulp.task( 'js', function () { gulp .src( './app/scripts/**/*.coffee' ) - .pipe( coffee() ) + .pipe( coffee({ + bare: true + }) ) .pipe( uglify() ) .pipe( gulp.dest( './.tmp/scripts' ) ); } ); gulp.task( 'js:test', function () { gulp .src( './test/**/*.coffee' ) - .pipe( coffee() ) - .pipe( uglify() ) + .pipe( coffee({ + bare: true + }) ) .pipe( gulp.dest( './.tmp' ) ); } ); diff --git a/routes/rest.js b/routes/rest.js index 44e3fd4..a6b68b3 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, diff --git a/test/protractor/j$.coffee b/test/protractor/j$.coffee index abd4ed2..8223b72 100644 --- a/test/protractor/j$.coffee +++ b/test/protractor/j$.coffee @@ -6,6 +6,6 @@ j$ = console.warn('finding', label) if label $(selector) input: (name) -> - $('#'+name) + element(protractor.By.css("[name=#{name}]")).getWebElement() module.exports = j$ diff --git a/test/protractor/pages/app-page.coffee b/test/protractor/pages/app-page.coffee index caa171e..1201180 100644 --- a/test/protractor/pages/app-page.coffee +++ b/test/protractor/pages/app-page.coffee @@ -2,6 +2,9 @@ ###* App Page - I handle general actions in the app. ### -module.exports = AppPage = () -> - @get = -> +AppPage = + title: $('.navbar-brand') + get: -> browser.get '/' + +module.exports = AppPage diff --git a/test/protractor/pages/login-page.coffee b/test/protractor/pages/login-page.coffee index 6a5c34e..562e0a9 100644 --- a/test/protractor/pages/login-page.coffee +++ b/test/protractor/pages/login-page.coffee @@ -1,10 +1,14 @@ ###* Login Page - I handle actions on the login page. ### -module.exports = LoginPage = () -> - @get = -> - browser.get '/#/login' - @login = (u, p) -> - j$.input('username').sendKeys(u) - j$.input('password').sendKeys(p) - j$.element('button[type="submit"]').click() +LoginPage = + username: $('#username') + password: $('#password') + get: -> + browser.get '/login' + login: (u, p) -> + @username.sendKeys(u) + @password.sendKeys(p) + element(protractor.By.css('button[type="submit"]')).click() + +module.exports = LoginPage diff --git a/test/protractor/pages/register-page.coffee b/test/protractor/pages/register-page.coffee index b6605d0..d9415c3 100644 --- a/test/protractor/pages/register-page.coffee +++ b/test/protractor/pages/register-page.coffee @@ -1,18 +1,23 @@ +j$ = require('../j$') + ###* Register Page - I handle actions on the register page ### -module.exports = RegisterPage = () -> - email = j$.input('email') - username = j$.input('username') - password = j$.input('password') - password2 = j$.input('password2') - agree = j$.input('agree') - @get = -> - browser.get '/#/register' - @register = -> - email.sendKeys('test@email.com') - username.sendKeys('test') - password.sendKeys('test') - password2.sendKeys('test') - agree.click() - element(protractor.By.css('button[type="submit"]')).click() +RegisterPage = + email = $('#email') + username: $('#username') + password: $('#password') + password2: $('#password2') + agree: $('#agree') + submit: element(protractor.By.css('button')) + get: -> + browser.get '/register' + register: (username, password) -> + @email.sendKeys(username) + @username.sendKeys(username) + @password.sendKeys(password) + @password2.sendKeys(password) + @agree.click() + @submit.click() + +module.exports = RegisterPage diff --git a/test/protractor/spec/app-spec.coffee b/test/protractor/spec/app-spec.coffee index 48c0234..a718865 100644 --- a/test/protractor/spec/app-spec.coffee +++ b/test/protractor/spec/app-spec.coffee @@ -1,15 +1,14 @@ -AppPage = require('../pages/app-page') +appPage = require('../pages/app-page') ###* Protractor e2e Tests ### -App = new AppPage() + describe "Angular-CMS App", -> beforeEach -> - App.get() - - #Welome Story: the initial page - describe 'Index:', -> - it "should display the main index view as default", -> - expect(browser.getLocationAbsUrl()).toEqual '/' + appPage.refresh() + it 'should have the correct title', -> + appPage.title.getText().then((val)-> + expect(val).toContain('angular-cms') + ) diff --git a/test/protractor/spec/login-spec.coffee b/test/protractor/spec/login-spec.coffee index fb20fc5..c0f5ae7 100644 --- a/test/protractor/spec/login-spec.coffee +++ b/test/protractor/spec/login-spec.coffee @@ -1,24 +1,12 @@ -LoginPage = require('../pages/login-page') -loginPage = new LoginPage() +loginPage = require('../pages/login-page') + ###* Login - The user login implementation ### describe 'Login:', -> - - #Click the login button each time beforeEach -> - $('a[href="#/login"]').click() - - #Make sure we end up at the login page to enter our credentials - #Make sure there is a username and password input with button + $('[href="#/login"]').click() it 'should have Username and password inputs with a button to submit the form', -> - expect(browser.getLocationAbsUrl()).toEqual '/login' - - #Login to the page - loginPage.login('test@email.com', 'test') - - #Wait for the api call to go thru - sleep 1 - - #We should end up at the dashboard page. - expect(browser.getLocationAbsUrl()).toEqual '/dashboard' + loginPage.login('test@email.com', 'test').then(()-> + expect(browser.getLocationAbsUrl()).toContain '/dashboard' + ) diff --git a/test/protractor/spec/register-spec.coffee b/test/protractor/spec/register-spec.coffee index f4a6692..16503af 100644 --- a/test/protractor/spec/register-spec.coffee +++ b/test/protractor/spec/register-spec.coffee @@ -1,16 +1,13 @@ -RegisterPage = require('../pages/register-page') -j$ = require('../j$') +registerPage = require('../pages/register-page') ###* Register - The user registration implementation ### +testEmail = Date.now() + '-test@email.com' describe 'Register: ', -> - it 'should have email and password inputs with a button to submit the form', -> - registerPage = new RegisterPage() + it 'should allow a user to register', -> registerPage.get() expect(browser.getCurrentUrl()).toContain 'register' - expect(j$.element('form', 'Login form').count()).toEqual 1 - expect(j$.element('input[name="email"]', 'Email input').count()).toEqual 1 - expect(j$.element('input[name="username"]', 'Username input').count()).toEqual 1 - expect(j$.element('input[name="password"]', 'Password input').count()).toEqual 2 - expect(j$.element('button[type="submit"]', 'Submit button').count()).toEqual 1 + registerPage.register(testEmail, 'test').then(()-> + expect(browser.getCurrentUrl()).toContain 'dashboard' + ) From 64aeaff1ad502b7b9c9956f74e547382a0b3840c Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Tue, 9 Dec 2014 10:49:57 -0800 Subject: [PATCH 37/39] updated specs --- gulpfile.js | 73 +++++++++++++++------- package.json | 4 +- test/protractor/j$.coffee | 14 ++--- test/protractor/pages/app-page.coffee | 9 +-- test/protractor/pages/login-page.coffee | 22 ++++--- test/protractor/pages/register-page.coffee | 32 +++++----- test/protractor/spec/app-spec.coffee | 16 ++--- test/protractor/spec/login-spec.coffee | 14 +++-- 8 files changed, 109 insertions(+), 75 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index e29d1eb..3a17851 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,28 +1,55 @@ -var coffee, gulp, uglify; +'use strict'; -gulp = require( 'gulp' ); -coffee = require( 'gulp-coffee' ); -uglify = require( 'gulp-uglify' ); +var del = require('del'); +var gulp = require('gulp'); +var coffee = require('gulp-coffee'); +var uglify = require('gulp-uglify'); +var protractor = require('gulp-protractor').protractor; -gulp.task( 'js', function () { + +gulp.task('clean', function(cb) { + del(['build'], cb); +}); + +/** + * CoffeeScript Source Files + */ +gulp.task('js', function () { gulp - .src( './app/scripts/**/*.coffee' ) - .pipe( coffee({ + .src('./app/scripts/**/*.coffee') + .pipe(coffee({ bare: true - }) ) - .pipe( uglify() ) - .pipe( gulp.dest( './.tmp/scripts' ) ); -} ); -gulp.task( 'js:test', function () { - gulp - .src( './test/**/*.coffee' ) - .pipe( coffee({ + })) + .pipe(uglify()) + .pipe(gulp.dest('./.tmp/scripts')); +}); + +/** + * CoffeeScript Test Files + */ +gulp.task('js:test', function () { + gulp.src('./test/**/*.coffee') + .pipe(coffee({ bare: true - }) ) - .pipe( gulp.dest( './.tmp' ) ); -} ); - -gulp.task( 'watch', function () { - gulp.watch( './app/scripts/**/*.coffee', ['js'] ); - gulp.watch( './test/**/*.coffee', ['js:test'] ) -} ); + })).pipe(gulp.dest('./.tmp')); +}); + +gulp.task('watch', function () { + gulp.watch('./app/scripts/**/*.coffee', ['js']); + gulp.watch('./test/**/*.coffee', ['js:test']) +}); + + + + +gulp.task('test', ['js:test'], function(){ + gulp.src(['./.tmp/protractor/**/*-spec.js']) + .pipe(protractor({ + configFile: 'protractor.conf.js' + })) + .on('error', function (e) { + throw e; + }); +}); + +gulp.task('default', ['js:test', 'test']); \ No newline at end of file diff --git a/package.json b/package.json index 2686c2b..b0ff62f 100755 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "devDependencies": { "chai": "^1.10.0", "connect-proxy": "~1.0.2", + "del": "^1.1.0", "grunt": "~0.4.4", "grunt-angular-templates": "~0.5.1", "grunt-autoprefixer": "~0.4.0", @@ -97,6 +98,7 @@ "grunt-svgmin": "~0.2.0", "grunt-usemin": "~2.0.2", "gulp-ngmin": "^0.3.0", + "gulp-protractor": "0.0.11", "gulp-uglify": "^1.0.2", "jasmine-core": "^2.1.2", "jasmine-node": "~1.11.0", @@ -111,7 +113,7 @@ "karma-phantomjs-launcher": "~0.1", "load-grunt-tasks": "~0.2.0", "mocha": "^2.0.1", - "protractor": "^1.0.0", + "protractor": "^1.5.0", "supertest": "^0.15.0", "time-grunt": "~0.2.1" }, diff --git a/test/protractor/j$.coffee b/test/protractor/j$.coffee index 8223b72..76aa0ef 100644 --- a/test/protractor/j$.coffee +++ b/test/protractor/j$.coffee @@ -1,11 +1,9 @@ ###* J$ Helpers - I am test helpers ### -j$ = - element: (selector, label) -> - console.warn('finding', label) if label - $(selector) - input: (name) -> - element(protractor.By.css("[name=#{name}]")).getWebElement() - -module.exports = j$ +module.exports = + element: (selector, label) -> + console.warn('finding', label) if label + $(selector) + input: (name) -> + element(protractor.By.css("[name=#{name}]")).getWebElement() \ No newline at end of file diff --git a/test/protractor/pages/app-page.coffee b/test/protractor/pages/app-page.coffee index 1201180..585342a 100644 --- a/test/protractor/pages/app-page.coffee +++ b/test/protractor/pages/app-page.coffee @@ -1,10 +1,11 @@ - ###* App Page - I handle general actions in the app. ### AppPage = - title: $('.navbar-brand') - get: -> - browser.get '/' + title: $('.navbar-brand') + get: -> + browser.get '/#' + refresh: -> + browser.refresh() module.exports = AppPage diff --git a/test/protractor/pages/login-page.coffee b/test/protractor/pages/login-page.coffee index 562e0a9..15d0700 100644 --- a/test/protractor/pages/login-page.coffee +++ b/test/protractor/pages/login-page.coffee @@ -2,13 +2,19 @@ Login Page - I handle actions on the login page. ### LoginPage = - username: $('#username') - password: $('#password') - get: -> - browser.get '/login' - login: (u, p) -> - @username.sendKeys(u) - @password.sendKeys(p) - element(protractor.By.css('button[type="submit"]')).click() + username: $('#username') + password: $('#password') + get: -> + browser.get '#/login' + logout: -> + $('.dropdown-toggle').getWebElement().then((el)-> + el.click().then(()-> + $('[href="#/login"]').click() + ) + ) + login: (u, p) -> + @username.sendKeys(u) + @password.sendKeys(p) + element(protractor.By.css('button[type="submit"]')).click() module.exports = LoginPage diff --git a/test/protractor/pages/register-page.coffee b/test/protractor/pages/register-page.coffee index d9415c3..321dba9 100644 --- a/test/protractor/pages/register-page.coffee +++ b/test/protractor/pages/register-page.coffee @@ -4,20 +4,22 @@ j$ = require('../j$') Register Page - I handle actions on the register page ### RegisterPage = - email = $('#email') - username: $('#username') - password: $('#password') - password2: $('#password2') - agree: $('#agree') - submit: element(protractor.By.css('button')) - get: -> - browser.get '/register' - register: (username, password) -> - @email.sendKeys(username) - @username.sendKeys(username) - @password.sendKeys(password) - @password2.sendKeys(password) - @agree.click() - @submit.click() + email: $('#email') + username: $('#username') + password: $('#password') + password2: $('#password2') + agree: $('#agree') + submit: element(protractor.By.buttonText('Sign up')) + get: -> + browser.get '#/register' + register: (username, password) -> + @email.sendKeys(username) + @username.sendKeys(username) + @password.sendKeys(password) + @password2.sendKeys(password) + @agree.click().then(()=> + @submit.click() + ) + module.exports = RegisterPage diff --git a/test/protractor/spec/app-spec.coffee b/test/protractor/spec/app-spec.coffee index a718865..9a8a9e6 100644 --- a/test/protractor/spec/app-spec.coffee +++ b/test/protractor/spec/app-spec.coffee @@ -1,14 +1,10 @@ -appPage = require('../pages/app-page') - - ###* Protractor e2e Tests ### -describe "Angular-CMS App", -> - beforeEach -> - appPage.refresh() - it 'should have the correct title', -> - appPage.title.getText().then((val)-> - expect(val).toContain('angular-cms') - ) +describe 'Angular-CMS App', -> + appPage = require('../pages/app-page') + it 'should have the correct title', -> + appPage.title.getText().then((val)-> + expect(val).toContain('angular-cms') + ) diff --git a/test/protractor/spec/login-spec.coffee b/test/protractor/spec/login-spec.coffee index c0f5ae7..1827900 100644 --- a/test/protractor/spec/login-spec.coffee +++ b/test/protractor/spec/login-spec.coffee @@ -4,9 +4,11 @@ loginPage = require('../pages/login-page') Login - The user login implementation ### describe 'Login:', -> - beforeEach -> - $('[href="#/login"]').click() - it 'should have Username and password inputs with a button to submit the form', -> - loginPage.login('test@email.com', 'test').then(()-> - expect(browser.getLocationAbsUrl()).toContain '/dashboard' - ) + beforeEach -> + loginPage.get() + afterEach -> + loginPage.logout() + it 'should have Username and password inputs with a button to submit the form', -> + loginPage.login('test@email.com', 'test').then(()-> + expect(browser.getLocationAbsUrl()).toContain '/dashboard' + ) From 44ad4693f643836fbfc8ab7d387d6982a39a71bb Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Tue, 9 Dec 2014 10:57:59 -0800 Subject: [PATCH 38/39] fixed login service --- app/scripts/controllers/login.coffee | 26 +-------------- app/scripts/services/cmsauthservice.coffee | 37 +++++++++++++++++----- test/protractor/pages/register-page.coffee | 1 + test/protractor/spec/login-spec.coffee | 2 +- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/app/scripts/controllers/login.coffee b/app/scripts/controllers/login.coffee index 331ae09..f4e70a2 100644 --- a/app/scripts/controllers/login.coffee +++ b/app/scripts/controllers/login.coffee @@ -17,30 +17,7 @@ angular.module('angularCmsApp').controller 'LoginCtrl', ($scope, $rootScope, $co setting the session and changing the location of the page. ### $scope.login = (u) -> - cmsAuthService.authorize(u).then( - (res)-> - - #Welcome the user - cmsNotify( '.login-message', 'success', 'Success!', "Welcome back.", 5000) - - #Set user session - session = - user: res.data.result - authorized: true - - #Set user cookie - cmsSessionService.setSession(session) - - #Set session on scope - $rootScope.App.session = session - - #Change location - $rootScope.App.location.path('/dashboard') - , - (err)-> - console.error(err) - cmsNotify( '.login-message', 'danger', 'Error!', err.data.message) - ) + cmsAuthService.login(u) ### Login Method to set the session. @@ -72,7 +49,6 @@ angular.module('angularCmsApp').controller 'LoginCtrl', ($scope, $rootScope, $co $scope.logout = (user) -> - #Clear cookie $cookieStore.put('App.session', null) diff --git a/app/scripts/services/cmsauthservice.coffee b/app/scripts/services/cmsauthservice.coffee index 29d2851..4cf8db2 100644 --- a/app/scripts/services/cmsauthservice.coffee +++ b/app/scripts/services/cmsauthservice.coffee @@ -10,10 +10,8 @@ This service will take care of authentication of a user, common methods include: * currentUser ### # AngularJS will instantiate a singleton by calling "new" on this function -angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $rootScope, $cookieStore, $location, cmsSessionService) -> - +angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $rootScope, $cookieStore, $location, cmsSessionService, cmsNotify) -> cmsAuthService = - #Endpoint location endpoint: '/api/v2' @@ -21,29 +19,52 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo authorize - I handle authorizing a user. ### authorize: (user) -> - return $http.post( @endpoint+"/login", user ) + return $http.post(@endpoint + "/login", user) ###* session - I handle getting a session. ### session: () -> - return $http.get( @endpoint+"/session" ) + return $http.get(@endpoint + "/session") ###* register - I handle register a user. ### register: (user) -> - return $http.post( @endpoint+"/register", user ) + return $http.post(@endpoint + "/register", user) ###* Logout method to clear the session. @param {Object} user - A user model containing remember ### logout: (user) -> - #Clear cookie cmsSessionService.logout(null) - $rootScope.apply(()-> $location.reload() ) + ###* + Login + ### + login: (user) -> + @authorize(user).then((res) -> + #Welcome the user + cmsNotify('.login-message', 'success', 'Success!', "Welcome back.", 5000) + + #Set user session + session = + user: res.data.result + authorized: true + + #Set user cookie + cmsSessionService.setSession(session) + + #Set session on scope + $rootScope.App.session = session + + #Change location + $rootScope.App.location.path('/dashboard') + , (err)-> + console.error(err) + cmsNotify('.login-message', 'danger', 'Error!', err.data.message) + ) diff --git a/test/protractor/pages/register-page.coffee b/test/protractor/pages/register-page.coffee index 321dba9..15c3d7e 100644 --- a/test/protractor/pages/register-page.coffee +++ b/test/protractor/pages/register-page.coffee @@ -19,6 +19,7 @@ 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 1827900..2439953 100644 --- a/test/protractor/spec/login-spec.coffee +++ b/test/protractor/spec/login-spec.coffee @@ -8,7 +8,7 @@ describe 'Login:', -> loginPage.get() afterEach -> loginPage.logout() - it 'should have Username and password inputs with a button to submit the form', -> + it 'should allow a user to login', -> loginPage.login('test@email.com', 'test').then(()-> expect(browser.getLocationAbsUrl()).toContain '/dashboard' ) From 42082a54133d14fe46c75bc5642740eabf09c43e Mon Sep 17 00:00:00 2001 From: Jonnie Spratley Date: Tue, 9 Dec 2014 11:01:34 -0800 Subject: [PATCH 39/39] updated regsiter service --- app/scripts/controllers/register.coffee | 27 ---------------------- app/scripts/services/cmsauthservice.coffee | 10 ++++++-- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/app/scripts/controllers/register.coffee b/app/scripts/controllers/register.coffee index 327e38b..a243883 100644 --- a/app/scripts/controllers/register.coffee +++ b/app/scripts/controllers/register.coffee @@ -22,30 +22,3 @@ angular.module('angularCmsApp').controller 'RegisterCtrl', ($scope, $location, $ $scope.register = (user)-> $log.info('register', user) - #Register the user - cmsAuthService.register(user).then( - (data)-> - #Login the user - cmsAuthService.authorize(user).then( - - $log.info(data) - - #Welcome the user - cmsNotify( '.message', 'info', 'Registered!', "You have registered as #{data.user.email}") - - #Set user session - session = - user: data.user - authorized: true - - #Set user cookie - cmsSessionService.setSession(session) - - #Change location - $location.path('/dashboard') - ) - , - (err) -> - $log.error(err) - cmsNotify( '.message', 'danger', 'Error!', err.data.message, 4000) - ) diff --git a/app/scripts/services/cmsauthservice.coffee b/app/scripts/services/cmsauthservice.coffee index 4cf8db2..8290b73 100644 --- a/app/scripts/services/cmsauthservice.coffee +++ b/app/scripts/services/cmsauthservice.coffee @@ -31,7 +31,13 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo register - I handle register a user. ### register: (user) -> - return $http.post(@endpoint + "/register", user) + $http.post(@endpoint + "/register", user).then( + (res)=> + @authorize(res.data) + , (err) -> + $log.error(err) + cmsNotify( '.message', 'danger', 'Error!', err.data.message, 4000) + ) ###* Logout method to clear the session. @@ -65,6 +71,6 @@ angular.module('angularCmsApp').service 'cmsAuthService', ($q, $http, $log, $roo #Change location $rootScope.App.location.path('/dashboard') , (err)-> - console.error(err) + $log.error(err) cmsNotify('.login-message', 'danger', 'Error!', err.data.message) )