'use strict';
module.exports = function (grunt) {
- var localConfig;
- try {
- localConfig = require('./server/config/local.env');
- } catch(e) {
- localConfig = {};
- }
-
- // Load grunt tasks automatically, when needed
- require('jit-grunt')(grunt, {
- express: 'grunt-express-server',
- useminPrepare: 'grunt-usemin',
- ngtemplates: 'grunt-angular-templates',
- cdnify: 'grunt-google-cdn',
- protractor: 'grunt-protractor-runner',
- buildcontrol: 'grunt-build-control'
- });
-
- // Time how long tasks take. Can help when optimizing build times
- require('time-grunt')(grunt);
-
- // Define the configuration for all the tasks
- grunt.initConfig({
-
- // Project settings
- pkg: grunt.file.readJSON('package.json'),
- yeoman: {
- // configurable paths
- client: require('./bower.json').appPath || 'client',
- dist: 'dist'
- },
- express: {
- options: {
- port: process.env.PORT || 9000
- },
- dev: {
- options: {
- script: 'server/app.js',
- debug: true
- }
- },
- prod: {
- options: {
- script: 'dist/server/app.js'
- }
- }
- },
- open: {
- server: {
- url: 'http://localhost:<%= express.options.port %>'
- }
- },
- watch: {
- injectJS: {
- files: [
- '<%= yeoman.client %>/{app,components}/**/*.js',
- '!<%= yeoman.client %>/{app,components}/**/*.spec.js',
- '!<%= yeoman.client %>/{app,components}/**/*.mock.js',
- '!<%= yeoman.client %>/app/app.js'],
- tasks: ['injector:scripts']
- },
- injectCss: {
- files: [
- '<%= yeoman.client %>/{app,components}/**/*.css'
- ],
- tasks: ['injector:css']
- },
- mochaTest: {
- files: ['server/**/*.spec.js'],
- tasks: ['env:test', 'mochaTest']
- },
- jsTest: {
- files: [
- '<%= yeoman.client %>/{app,components}/**/*.spec.js',
- '<%= yeoman.client %>/{app,components}/**/*.mock.js'
- ],
- tasks: ['newer:jshint:all', 'karma']
- },
- injectStylus: {
- files: [
- '<%= yeoman.client %>/{app,components}/**/*.styl'],
- tasks: ['injector:stylus']
- },
- stylus: {
- files: [
- '<%= yeoman.client %>/{app,components}/**/*.styl'],
- tasks: ['stylus', 'autoprefixer']
- },
- jade: {
- files: [
- '<%= yeoman.client %>/{app,components}/*',
- '<%= yeoman.client %>/{app,components}/**/*.jade'],
- tasks: ['jade']
- },
- gruntfile: {
- files: ['Gruntfile.js']
- },
- livereload: {
- files: [
- '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.css',
- '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.html',
-
- '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js',
-
- '!{.tmp,<%= yeoman.client %>}{app,components}/**/*.spec.js',
- '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js',
- '<%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'
- ],
- options: {
- livereload: true
- }
- },
- express: {
- files: [
- 'server/**/*.{js,json}'
- ],
- tasks: ['express:dev', 'wait'],
- options: {
- livereload: true,
- nospawn: true //Without this option specified express won't be reloaded
- }
- }
- },
-
- // Make sure code styles are up to par and there are no obvious mistakes
- jshint: {
- options: {
- jshintrc: '<%= yeoman.client %>/.jshintrc',
- reporter: require('jshint-stylish')
- },
- server: {
- options: {
- jshintrc: 'server/.jshintrc'
+ var localConfig;
+ try {
+ localConfig = require('./server/config/local.env');
+ } catch (e) {
+ localConfig = {};
+ }
+
+ // Load grunt tasks automatically, when needed
+ require('jit-grunt')(grunt, {
+ express: 'grunt-express-server',
+ useminPrepare: 'grunt-usemin',
+ ngtemplates: 'grunt-angular-templates',
+ cdnify: 'grunt-google-cdn',
+ protractor: 'grunt-protractor-runner',
+ buildcontrol: 'grunt-build-control'
+ });
+
+ // Time how long tasks take. Can help when optimizing build times
+ require('time-grunt')(grunt);
+
+ // Define the configuration for all the tasks
+ grunt.initConfig({
+
+ // Project settings
+ pkg: grunt.file.readJSON('package.json'),
+ yeoman: {
+ // configurable paths
+ client: require('./bower.json').appPath || 'client',
+ dist: 'dist'
},
- src: [
- 'server/**/*.js',
- '!server/**/*.spec.js'
- ]
- },
- serverTest: {
- options: {
- jshintrc: 'server/.jshintrc-spec'
+ express: {
+ options: {
+ port: process.env.PORT || 9000
+ },
+ dev: {
+ options: {
+ script: 'server/app.js',
+ debug: true
+ }
+ },
+ prod: {
+ options: {
+ script: 'dist/server/app.js'
+ }
+ }
},
- src: ['server/**/*.spec.js']
- },
- all: [
- '<%= yeoman.client %>/{app,components}/**/*.js',
- '!<%= yeoman.client %>/{app,components}/**/*.spec.js',
- '!<%= yeoman.client %>/{app,components}/**/*.mock.js'
- ],
- test: {
- src: [
- '<%= yeoman.client %>/{app,components}/**/*.spec.js',
- '<%= yeoman.client %>/{app,components}/**/*.mock.js'
- ]
- }
- },
-
- // Empties folders to start fresh
- clean: {
- dist: {
- files: [{
- dot: true,
- src: [
- '.tmp',
- '<%= yeoman.dist %>/*',
- '!<%= yeoman.dist %>/.git*',
- '!<%= yeoman.dist %>/.openshift',
- '!<%= yeoman.dist %>/Procfile'
- ]
- }]
- },
- server: '.tmp'
- },
-
- // Add vendor prefixed styles
- autoprefixer: {
- options: {
- browsers: ['last 1 version']
- },
- dist: {
- files: [{
- expand: true,
- cwd: '.tmp/',
- src: '{,*/}*.css',
- dest: '.tmp/'
- }]
- }
- },
-
- // Debugging with node inspector
- 'node-inspector': {
- custom: {
- options: {
- 'web-host': 'localhost'
- }
- }
- },
-
- // Use nodemon to run server in debug mode with an initial breakpoint
- nodemon: {
- debug: {
- script: 'server/app.js',
- options: {
- nodeArgs: ['--debug-brk'],
- env: {
- PORT: process.env.PORT || 9000
- },
- callback: function (nodemon) {
- nodemon.on('log', function (event) {
- console.log(event.colour);
- });
-
- // opens browser on initial server start
- nodemon.on('config:update', function () {
- setTimeout(function () {
- require('open')('http://localhost:8080/debug?port=5858');
- }, 500);
- });
- }
- }
- }
- },
-
- // Automatically inject Bower components into the app
- wiredep: {
- target: {
- src: '<%= yeoman.client %>/index.html',
- ignorePath: '<%= yeoman.client %>/',
- exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/ ]
- }
- },
-
- // Renames files for browser caching purposes
- rev: {
- dist: {
- files: {
- src: [
- '<%= yeoman.dist %>/public/{,*/}*.js',
- '<%= yeoman.dist %>/public/{,*/}*.css',
- '<%= yeoman.dist %>/public/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
- '<%= yeoman.dist %>/public/assets/fonts/*'
- ]
- }
- }
- },
-
- // Reads HTML for usemin blocks to enable smart builds that automatically
- // concat, minify and revision files. Creates configurations in memory so
- // additional tasks can operate on them
- useminPrepare: {
- html: ['<%= yeoman.client %>/index.html'],
- options: {
- dest: '<%= yeoman.dist %>/public'
- }
- },
-
- // Performs rewrites based on rev and the useminPrepare configuration
- usemin: {
- html: ['<%= yeoman.dist %>/public/{,*/}*.html'],
- css: ['<%= yeoman.dist %>/public/{,*/}*.css'],
- js: ['<%= yeoman.dist %>/public/{,*/}*.js'],
- options: {
- assetsDirs: [
- '<%= yeoman.dist %>/public',
- '<%= yeoman.dist %>/public/assets/images'
- ],
- // This is so we update image references in our ng-templates
- patterns: {
- js: [
- [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
- ]
- }
- }
- },
-
- // The following *-min tasks produce minified files in the dist folder
- imagemin: {
- dist: {
- cache: false,
- files: [{
- cache:false,
- expand: true,
- cwd: '<%= yeoman.client %>/assets/images',
- src: '{,*/}*.{png,jpg,jpeg,gif}',
- dest: '<%= yeoman.dist %>/public/assets/images'
- }]
- }
- },
-
- svgmin: {
- dist: {
- files: [{
- expand: true,
- cwd: '<%= yeoman.client %>/assets/images',
- src: '{,*/}*.svg',
- dest: '<%= yeoman.dist %>/public/assets/images'
- }]
- }
- },
-
- // Allow the use of non-minsafe AngularJS files. Automatically makes it
- // minsafe compatible so Uglify does not destroy the ng references
- ngAnnotate: {
- dist: {
- files: [{
- expand: true,
- cwd: '.tmp/concat',
- src: '**/*.js',
- dest: '.tmp/concat'
- }]
- }
- },
-
- // Package all the html partials into a single javascript payload
- ngtemplates: {
- options: {
- // This should be the name of your apps angular module
- module: 'liberValidApp',
- htmlmin: {
- collapseBooleanAttributes: true,
- collapseWhitespace: true,
- removeAttributeQuotes: true,
- removeEmptyAttributes: true,
- removeRedundantAttributes: true,
- removeScriptTypeAttributes: true,
- removeStyleLinkTypeAttributes: true
+ open: {
+ server: {
+ url: 'http://localhost:<%= express.options.port %>'
+ }
},
- usemin: 'app/app.js'
- },
- main: {
- cwd: '<%= yeoman.client %>',
- src: ['{app,components}/**/*.html'],
- dest: '.tmp/templates.js'
- },
- tmp: {
- cwd: '.tmp',
- src: ['{app,components}/**/*.html'],
- dest: '.tmp/tmp-templates.js'
- }
- },
-
- // Replace Google CDN references
- cdnify: {
- dist: {
- html: ['<%= yeoman.dist %>/public/*.html']
- }
- },
-
- // Copies remaining files to places other tasks can use
- copy: {
- dist: {
- files: [{
- expand: true,
- dot: true,
- cwd: '<%= yeoman.client %>',
- dest: '<%= yeoman.dist %>/public',
- src: [
- '*.{ico,png,txt}',
- '.htaccess',
- 'bower_components/**/*',
- 'assets/images/{,*/}*.{webp}',
- 'assets/fonts/**/*',
- 'index.html'
- ]
- }, {
- expand: true,
- cwd: '.tmp/images',
- dest: '<%= yeoman.dist %>/public/assets/images',
- src: ['generated/*']
- }, {
- expand: true,
- dest: '<%= yeoman.dist %>',
- src: [
- 'package.json',
- 'server/**/*'
- ]
- }]
- },
- styles: {
- expand: true,
- cwd: '<%= yeoman.client %>',
- dest: '.tmp/',
- src: ['{app,components}/**/*.css']
- }
- },
-
- buildcontrol: {
- options: {
- dir: 'dist',
- commit: true,
- push: true,
- connectCommits: false,
- message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
- },
- heroku: {
- options: {
- remote: 'heroku',
- branch: 'master'
- }
- },
- openshift: {
- options: {
- remote: 'openshift',
- branch: 'master'
- }
- }
- },
-
- // Run some tasks in parallel to speed up the build process
- concurrent: {
- server: [
- 'jade',
- 'stylus',
- ],
- test: [
- 'jade',
- 'stylus',
- ],
- debug: {
- tasks: [
- 'nodemon',
- 'node-inspector'
- ],
- options: {
- logConcurrentOutput: true
- }
- },
- dist: [
- 'jade',
- 'stylus',
- 'imagemin',
- 'svgmin'
- ]
- },
-
- // Test settings
- karma: {
- unit: {
- configFile: 'karma.conf.js',
- singleRun: true
- }
- },
-
- mochaTest: {
- options: {
- reporter: 'spec'
- },
- src: ['server/**/*.spec.js']
- },
-
- protractor: {
- options: {
- configFile: 'protractor.conf.js'
- },
- chrome: {
- options: {
- args: {
- browser: 'chrome'
- }
- }
- }
- },
-
- env: {
- test: {
- NODE_ENV: 'test'
- },
- prod: {
- NODE_ENV: 'production'
- },
- all: localConfig
- },
-
- // Compiles Jade to html
- jade: {
- compile: {
- options: {
- data: {
- debug: false
- }
+ watch: {
+ injectJS: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/**/*.js',
+ '!<%= yeoman.client %>/{app,components}/**/*.spec.js',
+ '!<%= yeoman.client %>/{app,components}/**/*.mock.js',
+ '!<%= yeoman.client %>/app/app.js'],
+ tasks: ['injector:scripts']
+ },
+ injectCss: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/**/*.css'
+ ],
+ tasks: ['injector:css']
+ },
+ mochaTest: {
+ files: ['server/**/*.spec.js'],
+ tasks: ['env:test', 'mochaTest']
+ },
+ jsTest: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/**/*.spec.js',
+ '<%= yeoman.client %>/{app,components}/**/*.mock.js'
+ ],
+ tasks: ['newer:jshint:all', 'karma']
+ },
+ injectStylus: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/**/*.styl'],
+ tasks: ['injector:stylus']
+ },
+ stylus: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/**/*.styl'],
+ tasks: ['stylus', 'autoprefixer']
+ },
+ jade: {
+ files: [
+ '<%= yeoman.client %>/{app,components}/*',
+ '<%= yeoman.client %>/{app,components}/**/*.jade'],
+ tasks: ['jade']
+ },
+ gruntfile: {
+ files: ['Gruntfile.js']
+ },
+ livereload: {
+ files: [
+ '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.css',
+ '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.html',
+
+ '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js',
+
+ '!{.tmp,<%= yeoman.client %>}{app,components}/**/*.spec.js',
+ '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js',
+ '<%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'
+ ],
+ options: {
+ livereload: true
+ }
+ },
+ express: {
+ files: [
+ 'server/**/*.{js,json}'
+ ],
+ tasks: ['express:dev', 'wait'],
+ options: {
+ livereload: true,
+ nospawn: true //Without this option specified express won't be reloaded
+ }
+ }
},
- files: [{
- expand: true,
- cwd: '<%= yeoman.client %>',
- src: [
- '{app,components}/**/*.jade'
- ],
- dest: '.tmp',
- ext: '.html'
- }]
- }
- },
-
- // Compiles Stylus to CSS
- stylus: {
- server: {
- options: {
- paths: [
- '<%= yeoman.client %>/bower_components',
- '<%= yeoman.client %>/app',
- '<%= yeoman.client %>/components'
- ],
- "include css": true
+
+ // Make sure code styles are up to par and there are no obvious mistakes
+ jshint: {
+ options: {
+ jshintrc: '<%= yeoman.client %>/.jshintrc',
+ reporter: require('jshint-stylish')
+ },
+ server: {
+ options: {
+ jshintrc: 'server/.jshintrc'
+ },
+ src: [
+ 'server/**/*.js',
+ '!server/**/*.spec.js'
+ ]
+ },
+ serverTest: {
+ options: {
+ jshintrc: 'server/.jshintrc-spec'
+ },
+ src: ['server/**/*.spec.js']
+ },
+ all: [
+ '<%= yeoman.client %>/{app,components}/**/*.js',
+ '!<%= yeoman.client %>/{app,components}/**/*.spec.js',
+ '!<%= yeoman.client %>/{app,components}/**/*.mock.js'
+ ],
+ test: {
+ src: [
+ '<%= yeoman.client %>/{app,components}/**/*.spec.js',
+ '<%= yeoman.client %>/{app,components}/**/*.mock.js'
+ ]
+ }
},
- files: {
- '.tmp/app/app.css' : '<%= yeoman.client %>/app/app.styl'
- }
- }
- },
-
- injector: {
- options: {
-
- },
- // Inject application script files into index.html (doesn't include bower)
- scripts: {
- options: {
- transform: function(filePath) {
- filePath = filePath.replace('/client/', '');
- filePath = filePath.replace('/.tmp/', '');
- return '<script src="' + filePath + '"></script>';
- },
- starttag: '<!-- injector:js -->',
- endtag: '<!-- endinjector -->'
+
+ // Empties folders to start fresh
+ clean: {
+ dist: {
+ files: [{
+ dot: true,
+ src: [
+ '.tmp',
+ '<%= yeoman.dist %>/*',
+ '!<%= yeoman.dist %>/.git*',
+ '!<%= yeoman.dist %>/.openshift',
+ '!<%= yeoman.dist %>/Procfile'
+ ]
+ }]
+ },
+ server: '.tmp'
+ },
+
+ // Add vendor prefixed styles
+ autoprefixer: {
+ options: {
+ browsers: ['last 1 version']
+ },
+ dist: {
+ files: [{
+ expand: true,
+ cwd: '.tmp/',
+ src: '{,*/}*.css',
+ dest: '.tmp/'
+ }]
+ }
+ },
+
+ // Debugging with node inspector
+ 'node-inspector': {
+ custom: {
+ options: {
+ 'web-host': 'localhost'
+ }
+ }
+ },
+
+ // Use nodemon to run server in debug mode with an initial breakpoint
+ nodemon: {
+ debug: {
+ script: 'server/app.js',
+ options: {
+ nodeArgs: ['--debug-brk'],
+ env: {
+ PORT: process.env.PORT || 9000
+ },
+ callback: function (nodemon) {
+ nodemon.on('log', function (event) {
+ console.log(event.colour);
+ });
+
+ // opens browser on initial server start
+ nodemon.on('config:update', function () {
+ setTimeout(function () {
+ require('open')('http://localhost:8080/debug?port=5858');
+ }, 500);
+ });
+ }
+ }
+ }
+ },
+
+ // Automatically inject Bower components into the app
+ wiredep: {
+ target: {
+ src: '<%= yeoman.client %>/index.html',
+ ignorePath: '<%= yeoman.client %>/',
+ exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/', /bootstrap.css/, /font-awesome.css/]
+ }
+ },
+
+ // Renames files for browser caching purposes
+ rev: {
+ dist: {
+ files: {
+ src: [
+ '<%= yeoman.dist %>/public/{,*/}*.js',
+ '<%= yeoman.dist %>/public/{,*/}*.css',
+ '<%= yeoman.dist %>/public/assets/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
+ '<%= yeoman.dist %>/public/assets/fonts/*'
+ ]
+ }
+ }
+ },
+
+ // Reads HTML for usemin blocks to enable smart builds that automatically
+ // concat, minify and revision files. Creates configurations in memory so
+ // additional tasks can operate on them
+ useminPrepare: {
+ html: ['<%= yeoman.client %>/index.html'],
+ options: {
+ dest: '<%= yeoman.dist %>/public'
+ }
+ },
+
+ // Performs rewrites based on rev and the useminPrepare configuration
+ usemin: {
+ html: ['<%= yeoman.dist %>/public/{,*/}*.html'],
+ css: ['<%= yeoman.dist %>/public/{,*/}*.css'],
+ js: ['<%= yeoman.dist %>/public/{,*/}*.js'],
+ options: {
+ assetsDirs: [
+ '<%= yeoman.dist %>/public',
+ '<%= yeoman.dist %>/public/assets/images'
+ ],
+ // This is so we update image references in our ng-templates
+ patterns: {
+ js: [
+ [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
+ ]
+ }
+ }
+ },
+
+ // The following *-min tasks produce minified files in the dist folder
+ imagemin: {
+ dist: {
+ cache: false,
+ files: [{
+ cache: false,
+ expand: true,
+ cwd: '<%= yeoman.client %>/assets/images',
+ src: '{,*/}*.{png,jpg,jpeg,gif}',
+ dest: '<%= yeoman.dist %>/public/assets/images'
+ }]
+ }
+ },
+
+ svgmin: {
+ dist: {
+ files: [{
+ expand: true,
+ cwd: '<%= yeoman.client %>/assets/images',
+ src: '{,*/}*.svg',
+ dest: '<%= yeoman.dist %>/public/assets/images'
+ }]
+ }
+ },
+
+ // Allow the use of non-minsafe AngularJS files. Automatically makes it
+ // minsafe compatible so Uglify does not destroy the ng references
+ ngAnnotate: {
+ dist: {
+ files: [{
+ expand: true,
+ cwd: '.tmp/concat',
+ src: '**/*.js',
+ dest: '.tmp/concat'
+ }]
+ }
+ },
+
+ // Package all the html partials into a single javascript payload
+ ngtemplates: {
+ options: {
+ // This should be the name of your apps angular module
+ module: 'liberValidApp',
+ htmlmin: {
+ collapseBooleanAttributes: true,
+ collapseWhitespace: true,
+ removeAttributeQuotes: true,
+ removeEmptyAttributes: true,
+ removeRedundantAttributes: true,
+ removeScriptTypeAttributes: true,
+ removeStyleLinkTypeAttributes: true
+ },
+ usemin: 'app/app.js'
+ },
+ main: {
+ cwd: '<%= yeoman.client %>',
+ src: ['{app,components}/**/*.html'],
+ dest: '.tmp/templates.js'
+ },
+ tmp: {
+ cwd: '.tmp',
+ src: ['{app,components}/**/*.html'],
+ dest: '.tmp/tmp-templates.js'
+ }
+ },
+
+ // Replace Google CDN references
+ cdnify: {
+ dist: {
+ html: ['<%= yeoman.dist %>/public/*.html']
+ }
},
- files: {
- '<%= yeoman.client %>/index.html': [
- [
-
- '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js',
-
- '!{.tmp,<%= yeoman.client %>}/app/app.js',
- '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.spec.js',
- '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js'
- ]
+
+ // Copies remaining files to places other tasks can use
+ copy: {
+ dist: {
+ files: [{
+ expand: true,
+ dot: true,
+ cwd: '<%= yeoman.client %>',
+ dest: '<%= yeoman.dist %>/public',
+ src: [
+ '*.{ico,png,txt}',
+ '.htaccess',
+ 'bower_components/**/*',
+ 'assets/images/{,*/}*.{webp}',
+ 'assets/fonts/**/*',
+ 'index.html'
+ ]
+ }, {
+ expand: true,
+ cwd: '.tmp/images',
+ dest: '<%= yeoman.dist %>/public/assets/images',
+ src: ['generated/*']
+ }, {
+ expand: true,
+ dest: '<%= yeoman.dist %>',
+ src: [
+ 'package.json',
+ 'server/**/*'
+ ]
+ }]
+ },
+ styles: {
+ expand: true,
+ cwd: '<%= yeoman.client %>',
+ dest: '.tmp/',
+ src: ['{app,components}/**/*.css']
+ }
+ },
+
+ buildcontrol: {
+ options: {
+ dir: 'dist',
+ commit: true,
+ push: true,
+ connectCommits: false,
+ message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
+ },
+ heroku: {
+ options: {
+ remote: 'heroku',
+ branch: 'master'
+ }
+ },
+ openshift: {
+ options: {
+ remote: 'openshift',
+ branch: 'master'
+ }
+ }
+ },
+
+ // Run some tasks in parallel to speed up the build process
+ concurrent: {
+ server: [
+ 'jade',
+ 'stylus',
+ ],
+ test: [
+ 'jade',
+ 'stylus',
+ ],
+ debug: {
+ tasks: [
+ 'nodemon',
+ 'node-inspector'
+ ],
+ options: {
+ logConcurrentOutput: true
+ }
+ },
+ dist: [
+ 'jade',
+ 'stylus',
+ 'imagemin',
+ 'svgmin'
]
- }
- },
-
- // Inject component styl into app.styl
- stylus: {
- options: {
- transform: function(filePath) {
- filePath = filePath.replace('/client/app/', '');
- filePath = filePath.replace('/client/components/', '');
- return '@import \'' + filePath + '\';';
- },
- starttag: '// injector',
- endtag: '// endinjector'
},
- files: {
- '<%= yeoman.client %>/app/app.styl': [
- '<%= yeoman.client %>/{app,components}/**/*.styl',
- '!<%= yeoman.client %>/app/app.styl'
- ]
- }
- },
-
- // Inject component css into index.html
- css: {
- options: {
- transform: function(filePath) {
- filePath = filePath.replace('/client/', '');
- filePath = filePath.replace('/.tmp/', '');
- return '<link rel="stylesheet" href="' + filePath + '">';
- },
- starttag: '<!-- injector:css -->',
- endtag: '<!-- endinjector -->'
+
+ // Test settings
+ karma: {
+ unit: {
+ configFile: 'karma.conf.js',
+ singleRun: true
+ }
},
- files: {
- '<%= yeoman.client %>/index.html': [
- '<%= yeoman.client %>/{app,components}/**/*.css'
- ]
- }
- }
- },
- });
- // Used for delaying livereload until after server has restarted
- grunt.registerTask('wait', function () {
- grunt.log.ok('Waiting for server reload...');
+ mochaTest: {
+ options: {
+ reporter: 'spec'
+ },
+ src: ['server/**/*.spec.js']
+ },
- var done = this.async();
+ mocha_istanbul: {
+ coverage: {
+ src: 'server', // a folder works nicely
+ options: {
+ mask: '**/*.spec.js'
+ }
+ },
+ istanbul_check_coverage: {
+ default: {
+ options: {
+ coverageFolder: 'coverage*', // will check both coverage folders and merge the coverage results
+ check: {
+ lines: 80,
+ statements: 80
+ }
+ }
+ }
+ }
+ },
- setTimeout(function () {
- grunt.log.writeln('Done waiting!');
- done();
- }, 1500);
- });
+ protractor: {
+ options: {
+ configFile: 'protractor.conf.js'
+ },
+ chrome: {
+ options: {
+ args: {
+ browser: 'chrome'
+ }
+ }
+ }
+ },
- grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
- this.async();
- });
+ env: {
+ test: {
+ NODE_ENV: 'test'
+ },
+ prod: {
+ NODE_ENV: 'production'
+ },
+ all: localConfig
+ },
- grunt.registerTask('serve', function (target) {
- if (target === 'dist') {
- return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']);
- }
+ // Compiles Jade to html
+ jade: {
+ compile: {
+ options: {
+ data: {
+ debug: false
+ }
+ },
+ files: [{
+ expand: true,
+ cwd: '<%= yeoman.client %>',
+ src: [
+ '{app,components}/**/*.jade'
+ ],
+ dest: '.tmp',
+ ext: '.html'
+ }]
+ }
+ },
- if (target === 'debug') {
- return grunt.task.run([
- 'clean:server',
- 'env:all',
- 'injector:stylus',
- 'concurrent:server',
- 'injector',
- 'wiredep',
- 'autoprefixer',
- 'concurrent:debug'
- ]);
- }
+ // Compiles Stylus to CSS
+ stylus: {
+ server: {
+ options: {
+ paths: [
+ '<%= yeoman.client %>/bower_components',
+ '<%= yeoman.client %>/app',
+ '<%= yeoman.client %>/components'
+ ],
+ "include css": true
+ },
+ files: {
+ '.tmp/app/app.css': '<%= yeoman.client %>/app/app.styl'
+ }
+ }
+ },
- grunt.task.run([
- 'clean:server',
- 'env:all',
- 'injector:stylus',
- 'concurrent:server',
- 'injector',
- 'wiredep',
- 'autoprefixer',
- 'express:dev',
- 'wait',
- 'open',
- '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('test', function(target) {
- if (target === 'server') {
- return grunt.task.run([
- 'env:all',
- 'env:test',
- 'mochaTest'
- ]);
- }
+ injector: {
+ options: {},
+ // Inject application script files into index.html (doesn't include bower)
+ scripts: {
+ options: {
+ transform: function (filePath) {
+ filePath = filePath.replace('/client/', '');
+ filePath = filePath.replace('/.tmp/', '');
+ return '<script src="' + filePath + '"></script>';
+ },
+ starttag: '<!-- injector:js -->',
+ endtag: '<!-- endinjector -->'
+ },
+ files: {
+ '<%= yeoman.client %>/index.html': [
+ [
+
+ '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js',
+
+ '!{.tmp,<%= yeoman.client %>}/app/app.js',
+ '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.spec.js',
+ '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js'
+ ]
+ ]
+ }
+ },
+
+ // Inject component styl into app.styl
+ stylus: {
+ options: {
+ transform: function (filePath) {
+ filePath = filePath.replace('/client/app/', '');
+ filePath = filePath.replace('/client/components/', '');
+ return '@import \'' + filePath + '\';';
+ },
+ starttag: '// injector',
+ endtag: '// endinjector'
+ },
+ files: {
+ '<%= yeoman.client %>/app/app.styl': [
+ '<%= yeoman.client %>/{app,components}/**/*.styl',
+ '!<%= yeoman.client %>/app/app.styl'
+ ]
+ }
+ },
+
+ // Inject component css into index.html
+ css: {
+ options: {
+ transform: function (filePath) {
+ filePath = filePath.replace('/client/', '');
+ filePath = filePath.replace('/.tmp/', '');
+ return '<link rel="stylesheet" href="' + filePath + '">';
+ },
+ starttag: '<!-- injector:css -->',
+ endtag: '<!-- endinjector -->'
+ },
+ files: {
+ '<%= yeoman.client %>/index.html': [
+ '<%= yeoman.client %>/{app,components}/**/*.css'
+ ]
+ }
+ }
+ },
+ });
- else if (target === 'client') {
- return grunt.task.run([
- 'clean:server',
- 'env:all',
- 'injector:stylus',
- 'concurrent:test',
- 'injector',
- 'autoprefixer',
- 'karma'
- ]);
- }
+ // Used for delaying livereload until after server has restarted
+ grunt.registerTask('wait', function () {
+ grunt.log.ok('Waiting for server reload...');
+
+ var done = this.async();
+
+ setTimeout(function () {
+ grunt.log.writeln('Done waiting!');
+ done();
+ }, 1500);
+ });
+
+ grunt.registerTask('express-keepalive', 'Keep grunt running', function () {
+ this.async();
+ });
+
+ grunt.registerTask('serve', function (target) {
+ if (target === 'dist') {
+ return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']);
+ }
- else if (target === 'e2e') {
- return grunt.task.run([
- 'clean:server',
- 'env:all',
- 'env:test',
- 'injector:stylus',
- 'concurrent:test',
+ if (target === 'debug') {
+ return grunt.task.run([
+ 'clean:server',
+ 'env:all',
+ 'injector:stylus',
+ 'concurrent:server',
+ 'injector',
+ 'wiredep',
+ 'autoprefixer',
+ 'concurrent:debug'
+ ]);
+ }
+
+ grunt.task.run([
+ 'clean:server',
+ 'env:all',
+ 'injector:stylus',
+ 'concurrent:server',
+ 'injector',
+ 'wiredep',
+ 'autoprefixer',
+ 'express:dev',
+ 'wait',
+ 'open',
+ '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('test', function (target) {
+ if (target === 'server') {
+ return grunt.task.run([
+ 'env:all',
+ 'env:test',
+ 'mochaTest'
+ ]);
+ }
+
+ else if (target === 'client') {
+ return grunt.task.run([
+ 'clean:server',
+ 'env:all',
+ 'injector:stylus',
+ 'concurrent:test',
+ 'injector',
+ 'autoprefixer',
+ 'karma'
+ ]);
+ }
+
+ else if (target === 'e2e') {
+ return grunt.task.run([
+ 'clean:server',
+ 'env:all',
+ 'env:test',
+ 'injector:stylus',
+ 'concurrent:test',
+ 'injector',
+ 'wiredep',
+ 'autoprefixer',
+ 'express:dev',
+ 'protractor'
+ ]);
+ }
+
+ else grunt.task.run([
+ 'test:server',
+ 'test:client'
+ ]);
+ });
+
+ grunt.registerTask('coverage', function (target) {
+ return grunt.task.run([
+ 'env:all',
+ 'env:test',
+ 'mocha_istanbul:coverage'
+ ]);
+ });
+
+ grunt.registerTask('build', [
+ 'clean:dist',
+ 'injector:stylus',
+ 'concurrent:dist',
'injector',
'wiredep',
+ 'useminPrepare',
'autoprefixer',
- 'express:dev',
- 'protractor'
- ]);
- }
+ 'ngtemplates',
+ 'concat',
+ 'ngAnnotate',
+ 'copy:dist',
+ 'cdnify',
+ 'cssmin',
+ 'uglify',
+ 'rev',
+ 'usemin'
+ ]);
- else grunt.task.run([
- 'test:server',
- 'test:client'
+ grunt.registerTask('default', [
+ 'newer:jshint',
+ 'test',
+ 'build'
]);
- });
-
- grunt.registerTask('build', [
- 'clean:dist',
- 'injector:stylus',
- 'concurrent:dist',
- 'injector',
- 'wiredep',
- 'useminPrepare',
- 'autoprefixer',
- 'ngtemplates',
- 'concat',
- 'ngAnnotate',
- 'copy:dist',
- 'cdnify',
- 'cssmin',
- 'uglify',
- 'rev',
- 'usemin'
- ]);
-
- grunt.registerTask('default', [
- 'newer:jshint',
- 'test',
- 'build'
- ]);
};
var request = require('supertest');
var jwt = require('jsonwebtoken');
var User = require('../user/user.model');
+var Report = require('../report/report.model');
var config = require('../../config/environment');
+var fs = require('fs');
+var path = require('path');
-var user = new User({
- provider: 'local',
- name: 'Fake User',
- email: 'test@test.com',
- password: 'password'
+var appDir = path.dirname(require.resolve('../../app'));
+
+var localMock = (function () {
+ var privUser;
+ var privReport;
+
+ var base64PDFData =
+ 'JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2Vz' +
+ 'IDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMg' +
+ 'WzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+Pgpl' +
+ 'bmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAg' +
+ 'ICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAg' +
+ 'ICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAg' +
+ 'ICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+Pgog' +
+ 'ICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoK' +
+ 'CjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAg' +
+ 'IDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYK' +
+ 'MCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAw' +
+ 'MDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAg' +
+ 'PDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==';
+
+
+ var token = function () {
+ privUser.authenticate('password');
+ return jwt.sign({_id: privUser._id}, config.secrets.session, {expiresIn: 60 * 60 * 5});
+ };
+
+
+ var generateUserObj = function (isAdmin) {
+ return new User({
+ provider: 'local',
+ name: 'Fake User',
+ email: 'test@test.com',
+ password: 'password',
+ role: isAdmin ? 'admin' : undefined
+ });
+ };
+
+ var generateReportObj = function () {
+ return new Report({
+ uuid: 'fakeuuid',
+ user: privUser._id,
+ time: Date.now(),
+ referential: privUser.referential ? privUser.referential : {},
+ filename: 'fakefile.pdf',
+ content: 'fakefile.pdf',
+ signatures: [],
+ isGenerated: true
+ });
+ };
+
+ var createReport = function (cb) {
+ //Clear reports before testing
+ Report.remove().exec().then(function () {
+ privReport = generateReportObj();
+ privReport.save(cb)
+ });
+ };
+
+ var setUserId = function (userid, cb) {
+ privReport.user = userid;
+ privReport.save(cb)
+ };
+
+ var createUser = function (cb) {
+ // Clear users before testing
+ User.remove().exec().then(function () {
+ privUser = generateUserObj(false);
+ privUser.save(cb);
+ });
+ };
+
+ var makeUserAdmin = function (done) {
+ privUser.role = 'admin';
+ privUser.save(done);
+ };
+
+ var makeGenerating = function (done) {
+ privReport.isGenerated = false;
+ privReport.save(done);
+ };
+
+ var createEmptyPDF = function (done) {
+ var file = appDir + "/components/worker/generator/output/" + privReport.uuid + ".pdf";
+ fs.writeFile(file, base64PDFData, 'base64', done);
+ };
+
+ var getUser = function () {
+ return privUser;
+ };
+
+ var getReport = function () {
+ return privReport;
+ };
+
+ var beforeEach = function (cb) {
+ createUser(function () {
+ createReport(function () {
+ cb();
+ })
+ });
+ };
+
+ var afterEach = function (cb) {
+ User.remove().exec().then(function () {
+ Report.remove().exec().then(function () {
+ var filename = appDir + "/components/worker/generator/output/" + privReport.uuid + ".pdf";
+ try {
+ fs.accessSync(filename, fs.F_OK);
+ fs.unlinkSync(filename);
+ } catch (e) {
+ //Do nothing
+ }
+ cb();
+ });
+ });
+ };
+
+ privUser = generateUserObj(false);
+
+ return {
+ afterEach: afterEach,
+ beforeEach: beforeEach,
+ base64PDF: base64PDFData,
+ user: {
+ token: token,
+ create: createUser,
+ get: getUser,
+ admin: makeUserAdmin
+ },
+ report: {
+ setUserId: setUserId,
+ get: getReport,
+ makeGenerating: makeGenerating,
+ createEmptyPDF: createEmptyPDF
+ }
+ }
+})();
+
+describe('GET /api/reports', function () {
+ beforeEach(localMock.beforeEach);
+
+ afterEach(localMock.afterEach);
+
+ it('should list with JSON array for admin', function (done) {
+ localMock.user.admin(function () {
+ request(app)
+ .get('/api/reports?access_token=' + localMock.user.token())
+ .expect(200)
+ .expect('Content-Type', /json/)
+ .end(function (err, res) {
+ if (err) return done(err);
+ res.body.should.be.instanceof(Array);
+ res.body.length.should.be.exactly(1);
+ done();
+ });
+ });
+ });
+
+ it('should be forbidden for non admin users', function (done) {
+ request(app)
+ .get('/api/reports?access_token=' + localMock.user.token())
+ .expect(403, done);
+ });
});
-describe('GET /api/reports', function() {
- before(function(done) {
- // Clear users before testing
- User.remove().exec().then(function() {
- user.save(function() {
- done();
- });
- });
- });
-
- afterEach(function(done) {
- User.remove().exec().then(function() {
- done();
- });
- });
-
-
- it('should respond with JSON array', function(done) {
- user.authenticate('password');
- var token = jwt.sign({_id: user._id }, config.secrets.session, { expiresIn: 60*60*5 });
- request(app)
- .get('/api/reports?access_token=' + token)
- .expect(200)
- .expect('Content-Type', /json/)
- .end(function(err, res) {
- if (err) return done(err);
- res.body.should.be.instanceof(Array);
- done();
- });
- });
+describe('GET /api/reports/:id', function () {
+ beforeEach(localMock.beforeEach);
+
+ afterEach(localMock.afterEach);
+
+ it('should be forbidden for guest users', function (done) {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id)
+ .expect(401, done);
+ });
+
+ it('should be forbidden for not owner users', function (done) {
+ localMock.report.setUserId('fakeUserId', function () {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(403, done);
+ });
+ });
+
+ it('should be not found for fake report ID', function (done) {
+ request(app)
+ .get('/api/reports/000000000000000000000001?access_token=' + localMock.user.token())
+ .expect(404, done);
+ });
+
+ it('should be \'gone\' for not existing file', function (done) {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(410, done);
+ });
+
+ it('should be \'accepted\' for generating report', function (done) {
+ localMock.report.makeGenerating(function () {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(202, done);
+ });
+ });
+
+ it('should be authorized for not owner admin', function (done) {
+ localMock.report.createEmptyPDF(function () {
+ localMock.report.setUserId('fakeUserId', function () {
+ localMock.user.admin(function () {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(200)
+ .expect('Content-Type', /pdf/)
+ .end(function (err) {
+ if (err) return done(err);
+ done();
+ });
+ });
+ });
+ });
+ });
+
+ it('should be authorized for owner user', function (done) {
+ localMock.report.createEmptyPDF(function () {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(200)
+ .expect('Content-Type', /pdf/)
+ .end(function (err) {
+ if (err) return done(err);
+ done();
+ });
+ });
+ });
+
+ it('should not be possible to download report twice', function (done) {
+ localMock.report.createEmptyPDF(function () {
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(200)
+ .expect('Content-Type', /pdf/)
+ .end(function (err) {
+ if (err) return done(err);
+ request(app)
+ .get('/api/reports/' + localMock.report.get()._id + '?access_token=' + localMock.user.token())
+ .expect(404, done);
+ });
+ });
+ });
});
+
+describe('POST /api/reports', function () {
+ beforeEach(localMock.beforeEach);
+
+ afterEach(localMock.afterEach);
+
+ it('should be forbidden for guest users', function (done) {
+ request(app)
+ .post('/api/reports')
+ .expect(401, done);
+ });
+
+ it('should be \'bad request\' when posting file is missing', function (done) {
+ request(app)
+ .post('/api/reports?access_token=' + localMock.user.token())
+ .expect(400, done);
+ });
+
+ it('should create report when file is sended', function (done) {
+ request(app)
+ .post('/api/reports?access_token=' + localMock.user.token())
+ .attach('content', appDir + '/api/report/fixtures/minimal.pdf')
+ .expect(200)
+ .end(function (err, res) {
+ if (err) return done(err);
+ res.body.id.should.be.instanceof(String);
+ Report.find(function (err, reports) {
+ if (err) return done(err);
+ reports.length.should.be.exactly(2);
+ done();
+ });
+ });
+ });
+
+ it('should create input directory for generator', function (done) {
+ request(app)
+ .post('/api/reports?access_token=' + localMock.user.token())
+ .attach('content', appDir + '/api/report/fixtures/minimal.pdf')
+ .expect(200)
+ .end(function (err, res) {
+ if (err) return done(err);
+ Report.findById(res.body.id, function (err, report) {
+ var file = appDir + '/components/worker/generator/input/' + report.uuid + '/minimal.pdf';
+ var ex;
+ try {
+ fs.accessSync(file, fs.F_OK);
+ } catch (e) {
+ ex = e;
+ }
+ done(ex);
+ });
+
+ });
+ });
+
+ it('should update report counter for user', function (done) {
+ request(app)
+ .post('/api/reports?access_token=' + localMock.user.token())
+ .attach('content', appDir + '/api/report/fixtures/minimal.pdf')
+ .expect(200)
+ .end(function (err) {
+ if (err) return done(err);
+ User.findById(localMock.user.get()._id, function (err, userFound) {
+ userFound.reportCounter.should.be.exactly(1);
+ done();
+ });
+
+ });
+
+ });
+
+});
\ No newline at end of file