├── .gitattributes ├── openshift ├── templates │ └── hot_deploy └── USAGE ├── app ├── templates │ ├── .buildignore │ ├── .gitattributes │ ├── client │ │ ├── robots.txt │ │ ├── app │ │ │ ├── admin(auth) │ │ │ │ ├── admin(less).less │ │ │ │ ├── admin(css).css │ │ │ │ ├── admin(sass).scss │ │ │ │ ├── admin(stylus).styl │ │ │ │ ├── admin.controller(coffee).coffee │ │ │ │ ├── admin(jade).jade │ │ │ │ ├── admin(coffee).coffee │ │ │ │ ├── admin.controller(js).js │ │ │ │ ├── admin(html).html │ │ │ │ └── admin(js).js │ │ │ ├── main │ │ │ │ ├── main(coffee).coffee │ │ │ │ ├── main(stylus).styl │ │ │ │ ├── main(js).js │ │ │ │ ├── main(css).css │ │ │ │ ├── main(less).less │ │ │ │ ├── main(sass).scss │ │ │ │ ├── main.controller(coffee).coffee │ │ │ │ ├── main.controller.spec(coffee).coffee │ │ │ │ ├── main.controller.spec(js).js │ │ │ │ ├── main.controller(js).js │ │ │ │ ├── main(jade).jade │ │ │ │ └── main(html).html │ │ │ ├── account(auth) │ │ │ │ ├── login │ │ │ │ │ ├── login(css).css │ │ │ │ │ ├── login(stylus).styl │ │ │ │ │ ├── login.controller(coffee).coffee │ │ │ │ │ ├── login.controller(js).js │ │ │ │ │ ├── login(less).less │ │ │ │ │ ├── login(sass).scss │ │ │ │ │ ├── login(jade).jade │ │ │ │ │ └── login(html).html │ │ │ │ ├── settings │ │ │ │ │ ├── settings.controller(coffee).coffee │ │ │ │ │ ├── settings.controller(js).js │ │ │ │ │ ├── settings(jade).jade │ │ │ │ │ └── settings(html).html │ │ │ │ ├── signup │ │ │ │ │ ├── signup.controller(coffee).coffee │ │ │ │ │ ├── signup.controller(js).js │ │ │ │ │ ├── signup(jade).jade │ │ │ │ │ └── signup(html).html │ │ │ │ ├── account(coffee).coffee │ │ │ │ └── account(js).js │ │ │ ├── app(less).less │ │ │ ├── app(sass).scss │ │ │ ├── app(coffee).coffee │ │ │ ├── app(css).css │ │ │ ├── app(stylus).styl │ │ │ └── app(js).js │ │ ├── favicon.ico │ │ ├── assets │ │ │ └── images │ │ │ │ └── !yeoman.png │ │ ├── components │ │ │ ├── socket(socketio) │ │ │ │ ├── socket.mock(coffee).coffee │ │ │ │ ├── socket.mock.js │ │ │ │ ├── socket.service(coffee).coffee │ │ │ │ └── socket.service.js │ │ │ ├── sql-error(auth) │ │ │ │ ├── sql-error.directive(coffee).coffee │ │ │ │ └── sql-error.directive(js).js │ │ │ ├── auth(auth) │ │ │ │ ├── user.service(coffee).coffee │ │ │ │ ├── user.service(js).js │ │ │ │ ├── auth.service(coffee).coffee │ │ │ │ └── auth.service(js).js │ │ │ ├── modal(uibootstrap) │ │ │ │ ├── modal(jade).jade │ │ │ │ ├── modal(stylus).styl │ │ │ │ ├── modal(css).css │ │ │ │ ├── modal(html).html │ │ │ │ ├── modal(less).less │ │ │ │ ├── modal(sass).scss │ │ │ │ ├── modal.service(coffee).coffee │ │ │ │ └── modal.service(js).js │ │ │ └── navbar │ │ │ │ ├── navbar.controller(coffee).coffee │ │ │ │ ├── navbar.controller(js).js │ │ │ │ ├── navbar(jade).jade │ │ │ │ └── navbar(html).html │ │ ├── .jshintrc │ │ └── index.html │ ├── .bowerrc │ ├── _.gitignore │ ├── .travis.yml │ ├── server │ │ ├── .jshintrc-spec │ │ ├── config │ │ │ ├── environment │ │ │ │ ├── test.js │ │ │ │ ├── development.js │ │ │ │ ├── production.js │ │ │ │ └── index.js │ │ │ ├── _local.env.js │ │ │ ├── _local.env.sample.js │ │ │ ├── socketio(socketio).js │ │ │ ├── seed(sql).js │ │ │ └── express.js │ │ ├── .jshintrc │ │ ├── api │ │ │ ├── thing │ │ │ │ ├── thing.model(sql).js │ │ │ │ ├── index.js │ │ │ │ ├── thing.spec.js │ │ │ │ ├── thing.socket(socketio).js │ │ │ │ └── thing.controller.js │ │ │ ├── user(auth) │ │ │ │ ├── index.js │ │ │ │ ├── user.spec.js │ │ │ │ ├── user.controller.js │ │ │ │ └── user.model.js │ │ │ └── index.js │ │ ├── components │ │ │ └── errors │ │ │ │ └── index.js │ │ ├── auth(auth) │ │ │ ├── twitter(twitterAuth) │ │ │ │ ├── index.js │ │ │ │ └── passport.js │ │ │ ├── facebook(facebookAuth) │ │ │ │ ├── index.js │ │ │ │ └── passport.js │ │ │ ├── local │ │ │ │ ├── index.js │ │ │ │ └── passport.js │ │ │ ├── google(googleAuth) │ │ │ │ ├── index.js │ │ │ │ └── passport.js │ │ │ ├── index.js │ │ │ └── auth.service.js │ │ ├── routes.js │ │ ├── app.js │ │ └── views │ │ │ ├── 404(jade).jade │ │ │ └── 404(html).html │ ├── e2e │ │ └── main │ │ │ ├── main.po.js │ │ │ └── main.spec.js │ ├── .editorconfig │ ├── _bower.json │ ├── protractor.conf.js │ ├── karma.conf.js │ └── _package.json ├── USAGE └── index.js ├── heroku ├── templates │ └── Procfile ├── USAGE └── index.js ├── generators ├── readme.md ├── value │ └── index.js ├── view │ └── index.js ├── constant │ └── index.js └── deploy │ └── index.js ├── test ├── fixtures │ ├── .bowerrc │ ├── bower.json │ ├── .yo-rc.json │ └── package.json └── readme.md ├── .gitignore ├── .travis.yml ├── .editorconfig ├── .jshintrc ├── route └── index.js ├── filter └── index.js ├── factory └── index.js ├── provider └── index.js ├── service └── index.js ├── controller └── index.js ├── decorator └── index.js ├── directive └── index.js ├── endpoint ├── templates │ ├── name.model(sql).js │ ├── index.js │ ├── name.socket(socketio).js │ ├── name.spec.js │ └── name.controller.js └── index.js ├── script-base.js ├── package.json ├── contributing.md ├── util.js └── Gruntfile.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /openshift/templates/hot_deploy: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/templates/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /app/templates/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /heroku/templates/Procfile: -------------------------------------------------------------------------------- 1 | web: node server/app.js 2 | -------------------------------------------------------------------------------- /generators/readme.md: -------------------------------------------------------------------------------- 1 | This folder is for deprecated generators only. -------------------------------------------------------------------------------- /test/fixtures/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/client/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /app/templates/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "client/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(less).less: -------------------------------------------------------------------------------- 1 | .trash { color:rgb(209, 91, 71); } -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(css).css: -------------------------------------------------------------------------------- 1 | .trash { color:rgb(209, 91, 71); } 2 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(sass).scss: -------------------------------------------------------------------------------- 1 | .trash { color:rgb(209, 91, 71); } 2 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(stylus).styl: -------------------------------------------------------------------------------- 1 | .trash 2 | color rgb(209, 91, 71) -------------------------------------------------------------------------------- /test/readme.md: -------------------------------------------------------------------------------- 1 | Run bower install and npm install in the fixtures folder before running tests -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates an full-stack AngularJS + Node app 3 | 4 | Example: 5 | yo angular-fullstack 6 | -------------------------------------------------------------------------------- /app/templates/client/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tashrafy/generator-sql-fullstack/HEAD/app/templates/client/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | test/temp 4 | demo 5 | .idea 6 | .DS_Store 7 | release.txt 8 | fixtures/bower.json 9 | fixtures/package.json -------------------------------------------------------------------------------- /app/templates/client/assets/images/!yeoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tashrafy/generator-sql-fullstack/HEAD/app/templates/client/assets/images/!yeoman.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.11' 5 | before_install: 6 | - gem update --system 7 | - gem install sass --version "=3.3.7" 8 | - npm install -g bower grunt-cli 9 | -------------------------------------------------------------------------------- /app/templates/_.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | .tmp<% if(filters.sass) { %> 4 | .sass-cache<% } %> 5 | .idea 6 | client/bower_components 7 | dist 8 | /server/config/local.env.js 9 | npm-debug.log 10 | -------------------------------------------------------------------------------- /app/templates/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.11' 5 | before_script: 6 | - npm install -g bower grunt-cli<% if (filters.sass) { %> 7 | - gem install sass<% } %> 8 | - bower install 9 | -------------------------------------------------------------------------------- /app/templates/server/.jshintrc-spec: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ".jshintrc", 3 | "globals": { 4 | "describe": true, 5 | "it": true, 6 | "before": true, 7 | "beforeEach": true, 8 | "after": true, 9 | "afterEach": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /heroku/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Initalizes a heroku app and generates a `dist` folder which is ready to push to heroku. 3 | 4 | Example: 5 | yo angular-fullstack:heroku 6 | 7 | This will create: 8 | a dist folder and initialize a heroku app 9 | -------------------------------------------------------------------------------- /openshift/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Initalizes an openshift app and generates a `dist` folder and pushes it to openshift. 3 | 4 | Example: 5 | yo angular-fullstack:openshift 6 | 7 | This will create: 8 | a dist folder and initialize an openshift app -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /app/templates/server/config/environment/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Test specific configuration 4 | // =========================== 5 | module.exports = { 6 | // MongoDB connection options 7 | mongo: { 8 | uri: 'mongodb://localhost/<%= _.slugify(appname) %>-test' 9 | } 10 | }; -------------------------------------------------------------------------------- /app/templates/client/components/socket(socketio)/socket.mock(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module 'socketMock', [] 4 | .factory 'socket', -> 5 | socket: 6 | connect: -> 7 | 8 | on: -> 9 | 10 | emit: -> 11 | 12 | receive: -> 13 | 14 | syncUpdates: -> 15 | unsyncUpdates: -> 16 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /route/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:route', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/route') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /filter/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:filter', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/filter') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /factory/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:factory', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/factory') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /provider/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:provider', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/provider') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /service/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:service', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/service') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /app/templates/server/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "eqeqeq": true, 6 | "immed": true, 7 | "latedef": "nofunc", 8 | "newcap": false, 9 | "noarg": true, 10 | "regexp": true, 11 | "undef": true, 12 | "smarttabs": true, 13 | "asi": true, 14 | "debug": true, 15 | "laxcomma": true 16 | } 17 | -------------------------------------------------------------------------------- /controller/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:controller', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/controller') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /decorator/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:decorator', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/decorator') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /directive/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var yeoman = require('yeoman-generator'); 3 | 4 | var Generator = yeoman.generators.Base.extend({ 5 | compose: function() { 6 | this.composeWith('ng-component:directive', {arguments: this.arguments}, { local: require.resolve('generator-ng-component/directive') }); 7 | } 8 | }); 9 | 10 | module.exports = Generator; -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'AdminCtrl', ($scope, $http, Auth, User) -> 5 | 6 | $http.get '/api/users' 7 | .success (users) -> 8 | $scope.users = users 9 | 10 | $scope.delete = (user) -> 11 | User.remove id: user._id 12 | _.remove $scope.users, user -------------------------------------------------------------------------------- /app/templates/client/components/sql-error(auth)/sql-error.directive(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | ### 4 | Removes server error when user updates input 5 | ### 6 | angular.module '<%= scriptAppName %>' 7 | .directive 'sqlError', -> 8 | restrict: 'A' 9 | require: 'ngModel' 10 | link: (scope, element, attrs, ngModel) -> 11 | element.on 'keydown', -> 12 | ngModel.$setValidity 'sql', true 13 | -------------------------------------------------------------------------------- /app/templates/client/components/auth(auth)/user.service(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .factory 'User', ($resource) -> 5 | $resource '/api/users/:id/:controller', 6 | id: '@_id' 7 | , 8 | changePassword: 9 | method: 'PUT' 10 | params: 11 | controller: 'password' 12 | 13 | get: 14 | method: 'GET' 15 | params: 16 | id: 'me' 17 | 18 | -------------------------------------------------------------------------------- /app/templates/client/components/socket(socketio)/socket.mock.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('socketMock', []) 4 | .factory('socket', function() { 5 | return { 6 | socket: { 7 | connect: function() {}, 8 | on: function() {}, 9 | emit: function() {}, 10 | receive: function() {} 11 | }, 12 | 13 | syncUpdates: function() {}, 14 | unsyncUpdates: function() {} 15 | }; 16 | }); -------------------------------------------------------------------------------- /app/templates/server/api/thing/thing.model(sql).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | var Thing = sequelize.define('Thing', { 5 | _id: { 6 | type: DataTypes.INTEGER, 7 | allowNull: false, 8 | primaryKey: true, 9 | autoIncrement: true 10 | }, 11 | name: DataTypes.STRING, 12 | info: DataTypes.STRING, 13 | active: DataTypes.BOOLEAN, 14 | }); 15 | 16 | return Thing; 17 | }; 18 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(jade).jade: -------------------------------------------------------------------------------- 1 | div(ng-include='"components/navbar/navbar.html"') 2 | .container 3 | p 4 | | The delete user and user index api routes are restricted to users with the 'admin' role. 5 | ul.list-group 6 | li.list-group-item(ng-repeat='user in users') 7 | strong {{user.name}} 8 | br 9 | span.text-muted {{user.email}} 10 | a.trash(ng-click='delete(user)') 11 | span.glyphicon.glyphicon-trash.pull-right -------------------------------------------------------------------------------- /generators/value/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var chalk = require('chalk'); 3 | var yeoman = require('yeoman-generator'); 4 | var util = require('util'); 5 | 6 | var Generator = module.exports = function Generator() { 7 | yeoman.generators.Base.apply(this, arguments); 8 | }; 9 | 10 | util.inherits(Generator, yeoman.generators.Base); 11 | 12 | Generator.prototype.deprecated = function deprecated() { 13 | this.log(chalk.yellow('This sub-generator is deprecated. \n')); 14 | }; -------------------------------------------------------------------------------- /generators/view/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var chalk = require('chalk'); 3 | var yeoman = require('yeoman-generator'); 4 | var util = require('util'); 5 | 6 | var Generator = module.exports = function Generator() { 7 | yeoman.generators.Base.apply(this, arguments); 8 | }; 9 | 10 | util.inherits(Generator, yeoman.generators.Base); 11 | 12 | Generator.prototype.deprecated = function deprecated() { 13 | this.log(chalk.yellow('This sub-generator is deprecated. \n')); 14 | }; -------------------------------------------------------------------------------- /generators/constant/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var chalk = require('chalk'); 3 | var yeoman = require('yeoman-generator'); 4 | var util = require('util'); 5 | 6 | var Generator = module.exports = function Generator() { 7 | yeoman.generators.Base.apply(this, arguments); 8 | }; 9 | 10 | util.inherits(Generator, yeoman.generators.Base); 11 | 12 | Generator.prototype.deprecated = function deprecated() { 13 | this.log(chalk.yellow('This sub-generator is deprecated. \n')); 14 | }; -------------------------------------------------------------------------------- /app/templates/client/app/main/main(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | <% if(filters.ngroute) { %>.config ($routeProvider) -> 5 | $routeProvider 6 | .when '/', 7 | templateUrl: 'app/main/main.html' 8 | controller: 'MainCtrl' 9 | <% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> 10 | $stateProvider 11 | .state 'main', 12 | url: '/' 13 | templateUrl: 'app/main/main.html' 14 | controller: 'MainCtrl' 15 | <% } %> -------------------------------------------------------------------------------- /endpoint/templates/name.model(sql).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(sequelize, DataTypes) { 4 | var <%= classedName %> = sequelize.define('<%= classedName %>', { 5 | _id: { 6 | type: DataTypes.INTEGER, 7 | allowNull: false, 8 | primaryKey: true, 9 | autoIncrement: true 10 | }, 11 | title: DataTypes.STRING, 12 | info: DataTypes.STRING, 13 | active: DataTypes.BOOLEAN, 14 | }); 15 | 16 | return <%= classedName %>; 17 | }; 18 | -------------------------------------------------------------------------------- /app/templates/e2e/main/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | this.heroEl = element(by.css('.hero-unit')); 10 | this.h1El = this.heroEl.element(by.css('h1')); 11 | this.imgEl = this.heroEl.element(by.css('img')); 12 | }; 13 | 14 | module.exports = new MainPage(); 15 | 16 | -------------------------------------------------------------------------------- /app/templates/server/components/errors/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error responses 3 | */ 4 | 5 | 'use strict'; 6 | 7 | module.exports[404] = function pageNotFound(req, res) { 8 | var viewFilePath = '404'; 9 | var statusCode = 404; 10 | var result = { 11 | status: statusCode 12 | }; 13 | 14 | res.status(result.status); 15 | res.render(viewFilePath, function (err) { 16 | if (err) { return res.json(result, result.status); } 17 | 18 | res.render(viewFilePath); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(jade).jade: -------------------------------------------------------------------------------- 1 | .modal-header 2 | button.close(ng-if='modal.dismissable', type='button', ng-click='$dismiss()') × 3 | h4.modal-title(ng-if='modal.title', ng-bind='modal.title') 4 | .modal-body 5 | p(ng-if='modal.text', ng-bind='modal.text') 6 | div(ng-if='modal.html', ng-bind-html='modal.html') 7 | .modal-footer 8 | button.btn(ng-repeat='button in modal.buttons', ng-class='button.classes', ng-click='button.click($event)', ng-bind='button.text') 9 | -------------------------------------------------------------------------------- /endpoint/templates/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var controller = require('./<%= name %>.controller'); 5 | 6 | var router = express.Router(); 7 | 8 | router.get('/', controller.index);<% if(filters.sql) { %> 9 | router.get('/:id', controller.show); 10 | router.post('/', controller.create); 11 | router.put('/:id', controller.update); 12 | router.patch('/:id', controller.update); 13 | router.delete('/:id', controller.destroy);<% } %> 14 | 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | <% if(filters.ngroute) { %>.config ($routeProvider) -> 5 | $routeProvider 6 | .when '/admin', 7 | templateUrl: 'app/admin/admin.html' 8 | controller: 'AdminCtrl' 9 | <% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> 10 | $stateProvider 11 | .state 'admin', 12 | url: '/admin' 13 | templateUrl: 'app/admin/admin.html' 14 | controller: 'AdminCtrl' 15 | <% } %> -------------------------------------------------------------------------------- /app/templates/server/api/thing/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var controller = require('./thing.controller'); 5 | 6 | var router = express.Router(); 7 | 8 | router.get('/', controller.index);<% if(filters.sql) { %> 9 | router.get('/:id', controller.show); 10 | router.post('/', controller.create); 11 | router.put('/:id', controller.update); 12 | router.patch('/:id', controller.update); 13 | router.delete('/:id', controller.destroy);<% } %> 14 | 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /app/templates/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /app/templates/e2e/main/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Main View', function() { 4 | var page; 5 | 6 | beforeEach(function() { 7 | browser.get('/'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | it('should include jumbotron with correct data', function() { 12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); 13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); 14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /app/templates/client/components/sql-error(auth)/sql-error.directive(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Removes server error when user updates input 5 | */ 6 | angular.module('<%= scriptAppName %>') 7 | .directive('sqlError', function () { 8 | return { 9 | restrict: 'A', 10 | require: 'ngModel', 11 | link: function(scope, element, attrs, ngModel) { 12 | element.on('keydown', function() { 13 | return ngModel.$setValidity('sql', true); 14 | }); 15 | } 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('AdminCtrl', function ($scope, $http, Auth, User) { 5 | 6 | // Use the User $resource to fetch all users 7 | $scope.users = User.query(); 8 | 9 | $scope.delete = function(user) { 10 | User.remove({ id: user._id }); 11 | angular.forEach($scope.users, function(u, i) { 12 | if (u === user) { 13 | $scope.users.splice(i, 1); 14 | } 15 | }); 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /app/templates/client/components/auth(auth)/user.service(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .factory('User', function ($resource) { 5 | return $resource('/api/users/:id/:controller', { 6 | id: '@_id' 7 | }, 8 | { 9 | changePassword: { 10 | method: 'PUT', 11 | params: { 12 | controller:'password' 13 | } 14 | }, 15 | get: { 16 | method: 'GET', 17 | params: { 18 | id:'me' 19 | } 20 | } 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(stylus).styl: -------------------------------------------------------------------------------- 1 | .modal-primary 2 | .modal-info 3 | .modal-success 4 | .modal-warning 5 | .modal-danger 6 | .modal-header 7 | color #fff 8 | border-radius 5px 5px 0 0 9 | 10 | .modal-primary .modal-header 11 | background #428bca 12 | 13 | .modal-info .modal-header 14 | background #5bc0de 15 | 16 | .modal-success .modal-header 17 | background #5cb85c 18 | 19 | .modal-warning .modal-header 20 | background #f0ad4e 21 | 22 | .modal-danger .modal-header 23 | background #d9534f 24 | -------------------------------------------------------------------------------- /app/templates/client/app/main/main(stylus).styl: -------------------------------------------------------------------------------- 1 | .thing-form 2 | margin 20px 0 3 | 4 | #banner 5 | border-bottom none 6 | margin-top -20px 7 | 8 | #banner h1 9 | font-size 60px 10 | letter-spacing -1px 11 | line-height 1 12 | 13 | .hero-unit 14 | background #4393B9 15 | color #F5F5F5 16 | padding 30px 15px 17 | position relative 18 | text-align center 19 | text-shadow 0 1px 0 rgba(0, 0, 0, 0.1) 20 | 21 | .footer 22 | border-top 1px solid #E5E5E5 23 | margin-top 70px 24 | padding 30px 0 25 | text-align center -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/twitter(twitterAuth)/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router 10 | .get('/', passport.authenticate('twitter', { 11 | failureRedirect: '/signup', 12 | session: false 13 | })) 14 | 15 | .get('/callback', passport.authenticate('twitter', { 16 | failureRedirect: '/signup', 17 | session: false 18 | }), auth.setTokenCookie); 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /app/templates/client/app/main/main(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | <% if(filters.ngroute) { %>.config(function ($routeProvider) { 5 | $routeProvider 6 | .when('/', { 7 | templateUrl: 'app/main/main.html', 8 | controller: 'MainCtrl' 9 | }); 10 | });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { 11 | $stateProvider 12 | .state('main', { 13 | url: '/', 14 | templateUrl: 'app/main/main.html', 15 | controller: 'MainCtrl' 16 | }); 17 | });<% } %> -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(html).html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

The delete user and user index api routes are restricted to users with the 'admin' role.

5 | 12 |
-------------------------------------------------------------------------------- /app/templates/server/api/thing/thing.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('should'); 4 | var app = require('../../app'); 5 | var request = require('supertest'); 6 | 7 | describe('GET /api/things', function() { 8 | 9 | it('should respond with JSON array', function(done) { 10 | request(app) 11 | .get('/api/things') 12 | .expect(200) 13 | .expect('Content-Type', /json/) 14 | .end(function(err, res) { 15 | if (err) return done(err); 16 | res.body.should.be.instanceof(Array); 17 | done(); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /app/templates/client/app/admin(auth)/admin(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | <% if(filters.ngroute) { %>.config(function ($routeProvider) { 5 | $routeProvider 6 | .when('/admin', { 7 | templateUrl: 'app/admin/admin.html', 8 | controller: 'AdminCtrl' 9 | }); 10 | });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { 11 | $stateProvider 12 | .state('admin', { 13 | url: '/admin', 14 | templateUrl: 'app/admin/admin.html', 15 | controller: 'AdminCtrl' 16 | }); 17 | });<% } %> -------------------------------------------------------------------------------- /app/templates/server/config/environment/development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Development specific configuration 4 | // ================================== 5 | module.exports = { 6 | // MongoDB connection options 7 | mongo: { 8 | uri: 'mongodb://localhost/<%= _.slugify(appname) %>-dev' 9 | }, 10 | 11 | // Postgres connection options 12 | postgres: { 13 | uri: process.env.POSTGRES_URL || 14 | 'postgres://user:pass@localhost:5432/<%= _.slugify(appname) %>' 15 | }, 16 | database: 'test', 17 | username: 'postgres', 18 | password: 'root', 19 | seedDB: true 20 | }; 21 | -------------------------------------------------------------------------------- /generators/deploy/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var chalk = require('chalk'); 3 | var yeoman = require('yeoman-generator'); 4 | var util = require('util'); 5 | 6 | var Generator = module.exports = function Generator() { 7 | yeoman.generators.Base.apply(this, arguments); 8 | }; 9 | 10 | util.inherits(Generator, yeoman.generators.NamedBase); 11 | 12 | Generator.prototype.deprecated = function deprecated() { 13 | this.log(chalk.yellow(chalk.bold('yo sql-fullstack:deploy') + ' is deprecated, instead use: \n') + 14 | chalk.green('yo sql:heroku') + ' or ' + chalk.green('yo sql:openshift')); 15 | }; 16 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/facebook(facebookAuth)/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router 10 | .get('/', passport.authenticate('facebook', { 11 | scope: ['email', 'user_about_me'], 12 | failureRedirect: '/signup', 13 | session: false 14 | })) 15 | 16 | .get('/callback', passport.authenticate('facebook', { 17 | failureRedirect: '/signup', 18 | session: false 19 | }), auth.setTokenCookie); 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(css).css: -------------------------------------------------------------------------------- 1 | .modal-primary .modal-header, 2 | .modal-info .modal-header, 3 | .modal-success .modal-header, 4 | .modal-warning .modal-header, 5 | .modal-danger .modal-header { 6 | color: #fff; 7 | border-radius: 5px 5px 0 0; 8 | } 9 | .modal-primary .modal-header { 10 | background: #428bca; 11 | } 12 | .modal-info .modal-header { 13 | background: #5bc0de; 14 | } 15 | .modal-success .modal-header { 16 | background: #5cb85c; 17 | } 18 | .modal-warning .modal-header { 19 | background: #f0ad4e; 20 | } 21 | .modal-danger .modal-header { 22 | background: #d9534f; 23 | } -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(html).html: -------------------------------------------------------------------------------- 1 | 5 | 9 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(less).less: -------------------------------------------------------------------------------- 1 | .modal-primary, 2 | .modal-info, 3 | .modal-success, 4 | .modal-warning, 5 | .modal-danger { 6 | .modal-header { 7 | color: #fff; 8 | border-radius: 5px 5px 0 0; 9 | } 10 | } 11 | .modal-primary .modal-header { 12 | background: @brand-primary; 13 | } 14 | .modal-info .modal-header { 15 | background: @brand-info; 16 | } 17 | .modal-success .modal-header { 18 | background: @brand-success; 19 | } 20 | .modal-warning .modal-header { 21 | background: @brand-warning; 22 | } 23 | .modal-danger .modal-header { 24 | background: @brand-danger; 25 | } 26 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal(sass).scss: -------------------------------------------------------------------------------- 1 | .modal-primary, 2 | .modal-info, 3 | .modal-success, 4 | .modal-warning, 5 | .modal-danger { 6 | .modal-header { 7 | color: #fff; 8 | border-radius: 5px 5px 0 0; 9 | } 10 | } 11 | .modal-primary .modal-header { 12 | background: $brand-primary; 13 | } 14 | .modal-info .modal-header { 15 | background: $brand-info; 16 | } 17 | .modal-success .modal-header { 18 | background: $brand-success; 19 | } 20 | .modal-warning .modal-header { 21 | background: $brand-warning; 22 | } 23 | .modal-danger .modal-header { 24 | background: $brand-danger; 25 | } 26 | -------------------------------------------------------------------------------- /app/templates/client/components/navbar/navbar.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'NavbarCtrl', ($scope, $location<% if(filters.auth) {%>, Auth<% } %>) -> 5 | $scope.menu = [ 6 | title: 'Home' 7 | link: '/' 8 | ] 9 | $scope.isCollapsed = true<% if(filters.auth) {%> 10 | $scope.isLoggedIn = Auth.isLoggedIn 11 | $scope.isAdmin = Auth.isAdmin 12 | $scope.getCurrentUser = Auth.getCurrentUser 13 | 14 | $scope.logout = -> 15 | Auth.logout() 16 | $location.path '/login'<% } %> 17 | 18 | $scope.isActive = (route) -> 19 | route is $location.path() -------------------------------------------------------------------------------- /app/templates/server/api/thing/thing.socket(socketio).js: -------------------------------------------------------------------------------- 1 | /** 2 | * Broadcast updates to client when the model changes 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var thing = require('./thing.model'); 8 | 9 | exports.register = function(socket) { 10 | // thing.schema.post('save', function (doc) { 11 | // onSave(socket, doc); 12 | // }); 13 | // thing.schema.post('remove', function (doc) { 14 | // onRemove(socket, doc); 15 | // }); 16 | } 17 | 18 | function onSave(socket, doc, cb) { 19 | socket.emit('thing:save', doc); 20 | } 21 | 22 | function onRemove(socket, doc, cb) { 23 | socket.emit('thing:remove', doc); 24 | } 25 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(css).css: -------------------------------------------------------------------------------- 1 | <% if (filters.oauth) { %><% if (filters.facebookAuth) { %>.btn-facebook { 2 | color: #fff; 3 | background-color: #3B5998; 4 | border-color: #133783; 5 | } 6 | <% } if (filters.twitterAuth) { %> 7 | .btn-twitter { 8 | color: #fff; 9 | background-color: #2daddc; 10 | border-color: #0271bf; 11 | } 12 | <% } if (filters.googleAuth) { %> 13 | .btn-google-plus { 14 | color: #fff; 15 | background-color: #dd4b39; 16 | border-color: #c53727; 17 | } 18 | <% } %> 19 | .btn-github { 20 | color: #fff; 21 | background-color: #fafafa; 22 | border-color: #ccc; 23 | }<% } %> 24 | -------------------------------------------------------------------------------- /app/templates/client/app/main/main(css).css: -------------------------------------------------------------------------------- 1 | .thing-form { 2 | margin: 20px 0; 3 | } 4 | 5 | #banner { 6 | border-bottom: none; 7 | margin-top: -20px; 8 | } 9 | 10 | #banner h1 { 11 | font-size: 60px; 12 | line-height: 1; 13 | letter-spacing: -1px; 14 | } 15 | 16 | .hero-unit { 17 | position: relative; 18 | padding: 30px 15px; 19 | color: #F5F5F5; 20 | text-align: center; 21 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); 22 | background: #4393B9; 23 | } 24 | 25 | .footer { 26 | text-align: center; 27 | padding: 30px 0; 28 | margin-top: 70px; 29 | border-top: 1px solid #E5E5E5; 30 | } -------------------------------------------------------------------------------- /app/templates/client/app/main/main(less).less: -------------------------------------------------------------------------------- 1 | .thing-form { 2 | margin: 20px 0; 3 | } 4 | 5 | #banner { 6 | border-bottom: none; 7 | margin-top: -20px; 8 | } 9 | 10 | #banner h1 { 11 | font-size: 60px; 12 | line-height: 1; 13 | letter-spacing: -1px; 14 | } 15 | 16 | .hero-unit { 17 | position: relative; 18 | padding: 30px 15px; 19 | color: #F5F5F5; 20 | text-align: center; 21 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); 22 | background: #4393B9; 23 | } 24 | 25 | .footer { 26 | text-align: center; 27 | padding: 30px 0; 28 | margin-top: 70px; 29 | border-top: 1px solid #E5E5E5; 30 | } -------------------------------------------------------------------------------- /app/templates/client/app/main/main(sass).scss: -------------------------------------------------------------------------------- 1 | .thing-form { 2 | margin: 20px 0; 3 | } 4 | 5 | #banner { 6 | border-bottom: none; 7 | margin-top: -20px; 8 | } 9 | 10 | #banner h1 { 11 | font-size: 60px; 12 | line-height: 1; 13 | letter-spacing: -1px; 14 | } 15 | 16 | .hero-unit { 17 | position: relative; 18 | padding: 30px 15px; 19 | color: #F5F5F5; 20 | text-align: center; 21 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1); 22 | background: #4393B9; 23 | } 24 | 25 | .footer { 26 | text-align: center; 27 | padding: 30px 0; 28 | margin-top: 70px; 29 | border-top: 1px solid #E5E5E5; 30 | } -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/settings/settings.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'SettingsCtrl', ($scope, User, Auth) -> 5 | $scope.errors = {} 6 | $scope.changePassword = (form) -> 7 | $scope.submitted = true 8 | 9 | if form.$valid 10 | Auth.changePassword $scope.user.oldPassword, $scope.user.newPassword 11 | .then -> 12 | $scope.message = 'Password successfully changed.' 13 | 14 | .catch -> 15 | form.password.$setValidity 'sql', false 16 | $scope.errors.other = 'Incorrect password' 17 | $scope.message = '' 18 | -------------------------------------------------------------------------------- /endpoint/templates/name.socket(socketio).js: -------------------------------------------------------------------------------- 1 | /** 2 | * Broadcast updates to client when the model changes 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var <%= classedName %> = require('./<%= name %>.model'); 8 | 9 | exports.register = function(socket) { 10 | <%= classedName %>.schema.post('save', function (doc) { 11 | onSave(socket, doc); 12 | }); 13 | <%= classedName %>.schema.post('remove', function (doc) { 14 | onRemove(socket, doc); 15 | }); 16 | } 17 | 18 | function onSave(socket, doc, cb) { 19 | socket.emit('<%= name %>:save', doc); 20 | } 21 | 22 | function onRemove(socket, doc, cb) { 23 | socket.emit('<%= name %>:remove', doc); 24 | } -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/local/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router.post('/', function(req, res, next) { 10 | passport.authenticate('local', function (err, user, info) { 11 | var error = err || info; 12 | if (error) return res.status(401).json(error); 13 | if (!user) return res.status(404).json({message: 'Something went wrong, please try again.'}); 14 | 15 | var token = auth.signToken(user._id, user.role); 16 | res.json({token: token}); 17 | })(req, res, next) 18 | }); 19 | 20 | module.exports = router; -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/google(googleAuth)/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var auth = require('../auth.service'); 6 | 7 | var router = express.Router(); 8 | 9 | router 10 | .get('/', passport.authenticate('google', { 11 | failureRedirect: '/signup', 12 | scope: [ 13 | 'https://www.googleapis.com/auth/userinfo.profile', 14 | 'https://www.googleapis.com/auth/userinfo.email' 15 | ], 16 | session: false 17 | })) 18 | 19 | .get('/callback', passport.authenticate('google', { 20 | failureRedirect: '/signup', 21 | session: false 22 | }), auth.setTokenCookie); 23 | 24 | module.exports = router; -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(stylus).styl: -------------------------------------------------------------------------------- 1 | <% if (filters.oauth) { %>// Social buttons 2 | // -------------------------------------------------- 3 | <% if (filters.facebookAuth) { %> 4 | .btn-facebook 5 | color: #fff; 6 | background-color: #3B5998; 7 | border-color: #133783; 8 | <% } if (filters.twitterAuth) { %> 9 | .btn-twitter 10 | color: #fff; 11 | background-color: #2daddc; 12 | border-color: #0271bf; 13 | <% } if (filters.googleAuth) { %> 14 | .btn-google-plus 15 | color: #fff; 16 | background-color: #dd4b39; 17 | border-color: #c53727; 18 | <% } %> 19 | .btn-github 20 | color: #fff; 21 | background-color: #fafafa; 22 | border-color: #ccc;<% } %> 23 | -------------------------------------------------------------------------------- /test/fixtures/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tempApp", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": ">=1.2.*", 6 | "json3": "~3.3.1", 7 | "es5-shim": "~3.0.1", 8 | "bootstrap-sass-official": "~3.1.1", 9 | "bootstrap": "~3.1.1", 10 | "angular-resource": ">=1.2.*", 11 | "angular-cookies": ">=1.2.*", 12 | "angular-sanitize": ">=1.2.*", 13 | "angular-route": ">=1.2.*", 14 | "angular-bootstrap": "~0.11.0", 15 | "font-awesome": ">=4.1.0", 16 | "lodash": "~2.4.1", 17 | "angular-socket-io": "~0.6.0", 18 | "angular-ui-router": "~0.2.10" 19 | }, 20 | "devDependencies": { 21 | "angular-mocks": ">=1.2.*", 22 | "angular-scenario": ">=1.2.*" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/templates/server/api/user(auth)/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express') 4 | , controller = require('./user.controller') 5 | , config = require('../../config/environment') 6 | , auth = require('../../auth/auth.service') 7 | ; 8 | 9 | var router = express.Router(); 10 | 11 | router.get('/', auth.hasRole('admin'), controller.index); 12 | router.delete('/:id', auth.hasRole('admin'), controller.destroy); 13 | router.get('/me', auth.isAuthenticated(), controller.me); 14 | router.put('/:id/password', auth.isAuthenticated(), controller.changePassword); 15 | router.get('/:id', auth.isAuthenticated(), controller.show); 16 | router.post('/', controller.create); 17 | 18 | module.exports = router; 19 | -------------------------------------------------------------------------------- /app/templates/client/components/navbar/navbar.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('NavbarCtrl', function ($scope, $location<% if(filters.auth) {%>, Auth<% } %>) { 5 | $scope.menu = [{ 6 | 'title': 'Home', 7 | 'link': '/' 8 | }]; 9 | 10 | $scope.isCollapsed = true;<% if(filters.auth) {%> 11 | $scope.isLoggedIn = Auth.isLoggedIn; 12 | $scope.isAdmin = Auth.isAdmin; 13 | $scope.getCurrentUser = Auth.getCurrentUser; 14 | 15 | $scope.logout = function() { 16 | Auth.logout(); 17 | $location.path('/login'); 18 | };<% } %> 19 | 20 | $scope.isActive = function(route) { 21 | return route === $location.path(); 22 | }; 23 | }); -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/settings/settings.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('SettingsCtrl', function ($scope, User, Auth) { 5 | $scope.errors = {}; 6 | 7 | $scope.changePassword = function(form) { 8 | $scope.submitted = true; 9 | if(form.$valid) { 10 | Auth.changePassword( $scope.user.oldPassword, $scope.user.newPassword ) 11 | .then( function() { 12 | $scope.message = 'Password successfully changed.'; 13 | }) 14 | .catch( function() { 15 | form.password.$setValidity('sql', false); 16 | $scope.errors.other = 'Incorrect password'; 17 | $scope.message = ''; 18 | }); 19 | } 20 | }; 21 | }); 22 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'LoginCtrl', ($scope, Auth, $location<% if(filters.oauth) {%>, $window<% } %>) -> 5 | $scope.user = {} 6 | $scope.errors = {} 7 | $scope.login = (form) -> 8 | $scope.submitted = true 9 | 10 | if form.$valid 11 | # Logged in, redirect to home 12 | Auth.login 13 | email: $scope.user.email 14 | password: $scope.user.password 15 | 16 | .then -> 17 | $location.path '/' 18 | 19 | .catch (err) -> 20 | $scope.errors.other = err.message 21 | <% if(filters.oauth) {%> 22 | $scope.loginOauth = (provider) -> 23 | $window.location.href = '/auth/' + provider<% } %> 24 | -------------------------------------------------------------------------------- /app/templates/server/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main application routes 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var errors = require('./components/errors'); 8 | var path = require('path'); 9 | 10 | module.exports = function(app) { 11 | 12 | // Insert routes below 13 | app.use('/api/things', require('./api/thing')); 14 | <% if (filters.auth) { %>app.use('/api/users', require('./api/user')); 15 | 16 | app.use('/auth', require('./auth')); 17 | <% } %> 18 | // All undefined asset or api routes should return a 404 19 | app.route('/:url(api|auth|components|app|bower_components|assets)/*') 20 | .get(errors[404]); 21 | 22 | // All other routes should redirect to the index.html 23 | app.route('/*') 24 | .get(function(req, res) { 25 | res.sendFile(path.resolve(app.get('appPath') + '/index.html')); 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /app/templates/client/app/app(less).less: -------------------------------------------------------------------------------- 1 | <% if(filters.bootstrap) { %>@import 'bootstrap/less/bootstrap.less';<% } %> 2 | @import 'font-awesome/less/font-awesome.less'; 3 | 4 | <% if(filters.bootstrap) { %>@icon-font-path: '/bower_components/bootstrap/fonts/';<% } %> 5 | @fa-font-path: '/bower_components/font-awesome/fonts'; 6 | 7 | /** 8 | * App-wide Styles 9 | */ 10 | 11 | .browsehappy { 12 | margin: 0.2em 0; 13 | background: #ccc; 14 | color: #000; 15 | padding: 0.2em 0; 16 | } 17 | <% if (!filters.bootstrap) { %> 18 | /* Responsive: Portrait tablets and up */ 19 | @media screen and (min-width: 768px) { 20 | .container { 21 | max-width: 730px; 22 | } 23 | } 24 | <% } %> 25 | // injector 26 | @import 'account/login/login.less'; 27 | @import 'admin/admin.less'; 28 | @import 'main/main.less'; 29 | // endinjector -------------------------------------------------------------------------------- /app/templates/client/app/main/main.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'MainCtrl', ($scope, $http<% if(filters.socketio) { %>, socket<% } %>) -> 5 | $scope.awesomeThings = [] 6 | 7 | $http.get('/api/things').success (awesomeThings) -> 8 | $scope.awesomeThings = awesomeThings 9 | <% if(filters.socketio) { %>socket.syncUpdates 'thing', $scope.awesomeThings<% } %> 10 | <% if(filters.sql) { %> 11 | $scope.addThing = -> 12 | return if $scope.newThing is '' 13 | $http.post '/api/things', 14 | name: $scope.newThing 15 | 16 | $scope.newThing = '' 17 | 18 | $scope.deleteThing = (thing) -> 19 | $http.delete '/api/things/' + thing._id<% } %><% if(filters.socketio) { %> 20 | 21 | $scope.$on '$destroy', -> 22 | socket.unsyncUpdates 'thing'<% } %> 23 | -------------------------------------------------------------------------------- /app/templates/server/config/_local.env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Use local.env.js for environment variables that grunt will set when the server starts locally. 4 | // Use for your api keys, secrets, etc. This file should not be tracked by git. 5 | // 6 | // You will need to set these on the server you deploy to. 7 | 8 | module.exports = { 9 | DOMAIN: 'http://localhost:9000', 10 | SESSION_SECRET: "<%= _.slugify(appname) + '-secret' %>",<% if (filters.facebookAuth) { %> 11 | 12 | FACEBOOK_ID: 'app-id', 13 | FACEBOOK_SECRET: 'secret',<% } if (filters.twitterAuth) { %> 14 | 15 | TWITTER_ID: 'app-id', 16 | TWITTER_SECRET: 'secret',<% } if (filters.googleAuth) { %> 17 | 18 | GOOGLE_ID: 'app-id', 19 | GOOGLE_SECRET: 'secret', 20 | <% } %> 21 | // Control debug level for modules using visionmedia/debug 22 | DEBUG: '' 23 | }; 24 | -------------------------------------------------------------------------------- /app/templates/client/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "jQuery": true, 23 | "angular": true, 24 | "console": true, 25 | "$": true, 26 | "_": true, 27 | "moment": true, 28 | "describe": true, 29 | "beforeEach": true, 30 | "module": true, 31 | "inject": true, 32 | "it": true, 33 | "expect": true, 34 | "browser": true, 35 | "element": true, 36 | "by": true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/templates/server/config/_local.env.sample.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Use local.env.js for environment variables that grunt will set when the server starts locally. 4 | // Use for your api keys, secrets, etc. This file should not be tracked by git. 5 | // 6 | // You will need to set these on the server you deploy to. 7 | 8 | module.exports = { 9 | DOMAIN: 'http://localhost:9000', 10 | SESSION_SECRET: '<%= _.slugify(appname) + "-secret" %>',<% if (filters.facebookAuth) { %> 11 | 12 | FACEBOOK_ID: 'app-id', 13 | FACEBOOK_SECRET: 'secret',<% } if (filters.twitterAuth) { %> 14 | 15 | TWITTER_ID: 'app-id', 16 | TWITTER_SECRET: 'secret',<% } if (filters.googleAuth) { %> 17 | 18 | GOOGLE_ID: 'app-id', 19 | GOOGLE_SECRET: 'secret',<% } %> 20 | 21 | // Control debug level for modules using visionmedia/debug 22 | DEBUG: '' 23 | }; 24 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/local/passport.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var LocalStrategy = require('passport-local').Strategy; 3 | 4 | exports.setup = function (User, config) { 5 | passport.use(new LocalStrategy({ 6 | usernameField: 'email', 7 | passwordField: 'password' // this is the virtual field on the model 8 | }, 9 | function(email, password, done) { 10 | User.findOne({ 11 | email: email.toLowerCase() 12 | }, function(err, user) { 13 | if (err) return done(err); 14 | 15 | if (!user) { 16 | return done(null, false, { message: 'This email is not registered.' }); 17 | } 18 | if (!user.authenticate(password)) { 19 | return done(null, false, { message: 'This password is not correct.' }); 20 | } 21 | return done(null, user); 22 | }); 23 | } 24 | )); 25 | }; -------------------------------------------------------------------------------- /script-base.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var yeoman = require('yeoman-generator'); 5 | var angularUtils = require('./util.js'); 6 | 7 | var Generator = module.exports = function Generator() { 8 | yeoman.generators.NamedBase.apply(this, arguments); 9 | 10 | try { 11 | this.appname = require(path.join(process.cwd(), 'bower.json')).name; 12 | } catch (e) { 13 | this.appname = path.basename(process.cwd()); 14 | } 15 | this.appname = this._.slugify(this._.humanize(this.appname)); 16 | this.scriptAppName = this._.camelize(this.appname) + angularUtils.appName(this); 17 | 18 | this.cameledName = this._.camelize(this.name); 19 | this.classedName = this._.classify(this.name); 20 | 21 | this.filters = this.config.get('filters'); 22 | this.sourceRoot(path.join(__dirname, '/templates')); 23 | }; 24 | 25 | util.inherits(Generator, yeoman.generators.NamedBase); -------------------------------------------------------------------------------- /app/templates/client/app/main/main.controller.spec(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | describe 'Controller: MainCtrl', -> 4 | 5 | # load the controller's module 6 | beforeEach module '<%= scriptAppName %>' <% if(filters.socketio) {%> 7 | beforeEach module 'socketMock' <% } %> 8 | 9 | MainCtrl = undefined 10 | scope = undefined 11 | $httpBackend = undefined 12 | 13 | # Initialize the controller and a mock scope 14 | beforeEach inject (_$httpBackend_, $controller, $rootScope) -> 15 | $httpBackend = _$httpBackend_ 16 | $httpBackend.expectGET('/api/things').respond [ 17 | 'HTML5 Boilerplate' 18 | 'AngularJS' 19 | 'Karma' 20 | 'Express' 21 | ] 22 | scope = $rootScope.$new() 23 | MainCtrl = $controller 'MainCtrl', 24 | $scope: scope 25 | 26 | it 'should attach a list of things to the scope', -> 27 | $httpBackend.flush() 28 | expect(scope.awesomeThings.length).toBe 4 -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('LoginCtrl', function ($scope, Auth, $location<% if (filters.oauth) { %>, $window<% } %>) { 5 | $scope.user = {}; 6 | $scope.errors = {}; 7 | 8 | $scope.login = function(form) { 9 | $scope.submitted = true; 10 | 11 | if(form.$valid) { 12 | Auth.login({ 13 | email: $scope.user.email, 14 | password: $scope.user.password 15 | }) 16 | .then( function() { 17 | // Logged in, redirect to home 18 | $location.path('/'); 19 | }) 20 | .catch( function(err) { 21 | $scope.errors.other = err.message; 22 | }); 23 | } 24 | }; 25 | <% if(filters.oauth) {%> 26 | $scope.loginOauth = function(provider) { 27 | $window.location.href = '/auth/' + provider; 28 | };<% } %> 29 | }); 30 | -------------------------------------------------------------------------------- /app/templates/client/app/app(sass).scss: -------------------------------------------------------------------------------- 1 | <% if(filters.bootstrap) { %>$icon-font-path: "/bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";<% } %> 2 | $fa-font-path: "/bower_components/font-awesome/fonts"; 3 | <% if(filters.bootstrap) { %> 4 | @import 'bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';<% } %> 5 | @import 'font-awesome/scss/font-awesome'; 6 | 7 | /** 8 | * App-wide Styles 9 | */ 10 | 11 | .browsehappy { 12 | margin: 0.2em 0; 13 | background: #ccc; 14 | color: #000; 15 | padding: 0.2em 0; 16 | } 17 | <% if (!filters.bootstrap) { %> 18 | /* Responsive: Portrait tablets and up */ 19 | @media screen and (min-width: 768px) { 20 | .container { 21 | max-width: 730px; 22 | } 23 | } 24 | <% } %> 25 | // Component styles are injected through grunt 26 | // injector 27 | @import 'account/login/login.scss'; 28 | @import 'admin/admin.scss'; 29 | @import 'main/main.scss'; 30 | // endinjector -------------------------------------------------------------------------------- /app/templates/server/config/environment/production.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Production specific configuration 4 | // ================================= 5 | module.exports = { 6 | // Server IP 7 | ip: process.env.OPENSHIFT_NODEJS_IP || 8 | process.env.IP || 9 | undefined, 10 | 11 | // Server port 12 | port: process.env.OPENSHIFT_NODEJS_PORT || 13 | process.env.PORT || 14 | 8080, 15 | 16 | // MongoDB connection options 17 | mongo: { 18 | uri: process.env.MONGOLAB_URI || 19 | process.env.MONGOHQ_URL || 20 | process.env.OPENSHIFT_MONGODB_DB_URL+process.env.OPENSHIFT_APP_NAME || 21 | 'mongodb://localhost/<%= _.slugify(appname) %>' 22 | }, 23 | 24 | // Postgres connection options 25 | postgres: { 26 | uri: process.env.POSTGRES_URL || 27 | 'postgres://user:pass@localhost:5432/<%= _.slugify(appname) %>' 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(_.humanize(appname)) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": ">=1.2.*", 6 | "json3": "~3.3.1", 7 | "es5-shim": "~3.0.1",<% if(filters.bootstrap) { %><% if (filters.sass) { %> 8 | "bootstrap-sass-official": "~3.1.1",<% } %> 9 | "bootstrap": "~3.1.1",<% } %> 10 | "angular-resource": ">=1.2.*", 11 | "angular-cookies": ">=1.2.*", 12 | "angular-sanitize": ">=1.2.*",<% if(filters.ngroute) { %> 13 | "angular-route": ">=1.2.*",<% } %><% if(filters.uibootstrap) { %> 14 | "angular-bootstrap": "~0.11.0",<% } %> 15 | "font-awesome": ">=4.1.0", 16 | "lodash": "~2.4.1"<% if(filters.socketio) { %>, 17 | "angular-socket-io": "~0.6.0"<% } %><% if(filters.uirouter) { %>, 18 | "angular-ui-router": "~0.2.10"<% } %> 19 | }, 20 | "devDependencies": { 21 | "angular-mocks": ">=1.2.*", 22 | "angular-scenario": ">=1.2.*" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/templates/client/app/main/main.controller.spec(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: MainCtrl', function () { 4 | // load the controller's module 5 | beforeEach(module('<%= scriptAppName %>'));<% if(filters.socketio) {%> 6 | beforeEach(module('socketMock'));<% } %> 7 | 8 | var MainCtrl, 9 | scope, 10 | $httpBackend; 11 | 12 | // Initialize the controller and a mock scope 13 | beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { 14 | $httpBackend = _$httpBackend_; 15 | $httpBackend.expectGET('/api/things') 16 | .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']); 17 | 18 | scope = $rootScope.$new(); 19 | MainCtrl = $controller('MainCtrl', { 20 | $scope: scope 21 | }); 22 | })); 23 | 24 | it('should attach a list of things to the scope', function () { 25 | $httpBackend.flush(); 26 | expect(scope.awesomeThings.length).toBe(4); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var passport = require('passport'); 5 | var config = require('../config/environment'); 6 | var User = require('../api').User; 7 | 8 | // Passport Configuration 9 | require('./local/passport').setup(User, config);<% if (filters.facebookAuth) { %> 10 | require('./facebook/passport').setup(User, config);<% } %><% if (filters.googleAuth) { %> 11 | require('./google/passport').setup(User, config);<% } %><% if (filters.twitterAuth) { %> 12 | require('./twitter/passport').setup(User, config);<% } %> 13 | 14 | var router = express.Router(); 15 | 16 | router.use('/local', require('./local'));<% if (filters.facebookAuth) { %> 17 | router.use('/facebook', require('./facebook'));<% } %><% if (filters.twitterAuth) { %> 18 | router.use('/twitter', require('./twitter'));<% } %><% if (filters.googleAuth) { %> 19 | router.use('/google', require('./google'));<% } %> 20 | 21 | module.exports = router; -------------------------------------------------------------------------------- /app/templates/client/app/main/main.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('MainCtrl', function ($scope, $http<% if(filters.socketio) { %>, socket<% } %>) { 5 | $scope.awesomeThings = []; 6 | 7 | $http.get('/api/things').success(function(awesomeThings) { 8 | $scope.awesomeThings = awesomeThings;<% if(filters.socketio) { %> 9 | socket.syncUpdates('thing', $scope.awesomeThings);<% } %> 10 | }); 11 | <% if(filters.sql) { %> 12 | $scope.addThing = function() { 13 | if($scope.newThing === '') { 14 | return; 15 | } 16 | $http.post('/api/things', { name: $scope.newThing }); 17 | $scope.newThing = ''; 18 | }; 19 | 20 | $scope.deleteThing = function(thing) { 21 | $http.delete('/api/things/' + thing._id); 22 | };<% } %><% if(filters.socketio) { %> 23 | 24 | $scope.$on('$destroy', function () { 25 | socket.unsyncUpdates('thing'); 26 | });<% } %> 27 | }); 28 | -------------------------------------------------------------------------------- /app/templates/server/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main application file 3 | */ 4 | 5 | 'use strict'; 6 | 7 | // Set default node environment to development 8 | process.env.NODE_ENV = process.env.NODE_ENV || 'development'; 9 | 10 | var express = require('express'); 11 | var config = require('./config/environment'); 12 | 13 | if (config.seedDB) { require('./config/seed'); } 14 | 15 | // Setup server 16 | var app = express(); 17 | var server = require('http').createServer(app);<% if (filters.socketio) { %> 18 | var socketio = require('socket.io')(server, { 19 | serveClient: config.env !== 'production', 20 | path: '/socket.io-client' 21 | }); 22 | require('./config/socketio')(socketio);<% } %> 23 | require('./config/express')(app); 24 | require('./routes')(app); 25 | 26 | // Start server 27 | server.listen(config.port, config.ip, function () { 28 | console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); 29 | }); 30 | 31 | // Expose app 32 | exports = module.exports = app; 33 | -------------------------------------------------------------------------------- /app/templates/server/api/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var fs = require("fs"); 4 | var path = require("path"); 5 | var Sequelize = require("sequelize"); 6 | var env = process.env.NODE_ENV || "development"; 7 | var config = require('../config/environment'); 8 | var sequelize = new Sequelize(config.sql.database, config.sql.username, config.sql.password, config.sql); 9 | var db = {}; 10 | 11 | fs 12 | .readdirSync(__dirname) 13 | .filter(function(file) { 14 | return (file.indexOf(".") !== 0) && (file !== "index.js"); 15 | }) 16 | .forEach(function(file) { 17 | file = '/' + file + '/' + file + '.model.js'; 18 | var model = sequelize["import"](path.join(__dirname, file)); 19 | db[model.name] = model; 20 | }); 21 | 22 | Object.keys(db).forEach(function(modelName) { 23 | if ("associate" in db[modelName]) { 24 | db[modelName].associate(db); 25 | } 26 | }); 27 | 28 | db.sequelize = sequelize; 29 | db.Sequelize = Sequelize; 30 | 31 | module.exports = db; 32 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/settings/settings(jade).jade: -------------------------------------------------------------------------------- 1 | div(ng-include='"components/navbar/navbar.html"') 2 | .container 3 | .row 4 | .col-sm-12 5 | h1 Change Password 6 | .col-sm-12 7 | form.form(name='form', ng-submit='changePassword(form)', novalidate='') 8 | .form-group 9 | label Current Password 10 | input.form-control(type='password', name='password', ng-model='user.oldPassword', sql-error='') 11 | p.help-block(ng-show='form.password.$error.sql') 12 | | {{ errors.other }} 13 | .form-group 14 | label New Password 15 | input.form-control(type='password', name='newPassword', ng-model='user.newPassword', ng-minlength='3', required='') 16 | p.help-block(ng-show='(form.newPassword.$error.minlength || form.newPassword.$error.required) && (form.newPassword.$dirty || submitted)') 17 | | Password must be at least 3 characters. 18 | 19 | p.help-block {{ message }} 20 | 21 | button.btn.btn-lg.btn-primary(type='submit') Save changes 22 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/signup/signup.controller(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .controller 'SignupCtrl', ($scope, Auth, $location<% if(filters.oauth) {%>, $window<% } %>) -> 5 | $scope.user = {} 6 | $scope.errors = {} 7 | $scope.register = (form) -> 8 | $scope.submitted = true 9 | 10 | if form.$valid 11 | # Account created, redirect to home 12 | Auth.createUser 13 | name: $scope.user.name 14 | email: $scope.user.email 15 | password: $scope.user.password 16 | 17 | .then -> 18 | $location.path '/' 19 | 20 | .catch (err) -> 21 | err = err.data 22 | $scope.errors = {} 23 | 24 | # Update validity of form fields that match the sql errors 25 | angular.forEach err.errors, (error, field) -> 26 | form[field].$setValidity 'sql', false 27 | $scope.errors[field] = error.message 28 | <% if(filters.oauth) {%> 29 | $scope.loginOauth = (provider) -> 30 | $window.location.href = '/auth/' + provider<% } %> 31 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/account(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | <% if(filters.ngroute) { %>.config ($routeProvider) -> 5 | $routeProvider 6 | .when '/login', 7 | templateUrl: 'app/account/login/login.html' 8 | controller: 'LoginCtrl' 9 | 10 | .when '/signup', 11 | templateUrl: 'app/account/signup/signup.html' 12 | controller: 'SignupCtrl' 13 | 14 | .when '/settings', 15 | templateUrl: 'app/account/settings/settings.html' 16 | controller: 'SettingsCtrl' 17 | authenticate: true 18 | <% } %><% if(filters.uirouter) { %>.config ($stateProvider) -> 19 | $stateProvider 20 | .state 'login', 21 | url: '/login' 22 | templateUrl: 'app/account/login/login.html' 23 | controller: 'LoginCtrl' 24 | 25 | .state 'signup', 26 | url: '/signup' 27 | templateUrl: 'app/account/signup/signup.html' 28 | controller: 'SignupCtrl' 29 | 30 | .state 'settings', 31 | url: '/settings' 32 | templateUrl: 'app/account/settings/settings.html' 33 | controller: 'SettingsCtrl' 34 | authenticate: true 35 | <% } %> -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/twitter(twitterAuth)/passport.js: -------------------------------------------------------------------------------- 1 | exports.setup = function (User, config) { 2 | var passport = require('passport'); 3 | var TwitterStrategy = require('passport-twitter').Strategy; 4 | 5 | passport.use(new TwitterStrategy({ 6 | consumerKey: config.twitter.clientID, 7 | consumerSecret: config.twitter.clientSecret, 8 | callbackURL: config.twitter.callbackURL 9 | }, 10 | function(token, tokenSecret, profile, done) { 11 | User.findOne({ 12 | 'twitter.id_str': profile.id 13 | }, function(err, user) { 14 | if (err) { 15 | return done(err); 16 | } 17 | if (!user) { 18 | user = new User({ 19 | name: profile.displayName, 20 | username: profile.username, 21 | role: 'user', 22 | provider: 'twitter', 23 | twitter: profile._json 24 | }); 25 | user.save(function(err) { 26 | if (err) return done(err); 27 | done(err, user); 28 | }); 29 | } else { 30 | return done(err, user); 31 | } 32 | }); 33 | } 34 | )); 35 | }; 36 | -------------------------------------------------------------------------------- /endpoint/templates/name.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('should'); 4 | var app = require('../../app'); 5 | var request = require('supertest'); 6 | var <%= classedName %> = app.get('models').<%= classedName %>; 7 | 8 | describe('GET <%= route %>', function() { 9 | 10 | <%= classedName %> 11 | .sync() 12 | .then(function() { 13 | return <%= classedName %>.destroy({ where: {} }); 14 | }) 15 | .then(function() { 16 | <%= classedName %> 17 | .create({ 18 | title: "Title", 19 | info: "Info", 20 | active: true, 21 | }) 22 | .then(function(){ 23 | it('should respond with JSON array', function(done) { 24 | request(app) 25 | .get('<%= route %>') 26 | .expect(200) 27 | .expect('Content-Type', /json/) 28 | .end(function(err, res) { 29 | if (err) return done(err); 30 | res.body.should.be.instanceof(Array); 31 | done(); 32 | }); 33 | }); 34 | }); 35 | }); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/google(googleAuth)/passport.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; 3 | 4 | exports.setup = function (User, config) { 5 | passport.use(new GoogleStrategy({ 6 | clientID: config.google.clientID, 7 | clientSecret: config.google.clientSecret, 8 | callbackURL: config.google.callbackURL 9 | }, 10 | function(accessToken, refreshToken, profile, done) { 11 | User.findOne({ 12 | 'google.id': profile.id 13 | }, function(err, user) { 14 | if (!user) { 15 | user = new User({ 16 | name: profile.displayName, 17 | email: profile.emails[0].value, 18 | role: 'user', 19 | username: profile.username, 20 | provider: 'google', 21 | google: profile._json 22 | }); 23 | user.save(function(err) { 24 | if (err) return done(err); 25 | done(err, user); 26 | }); 27 | } else { 28 | return done(err, user); 29 | } 30 | }); 31 | } 32 | )); 33 | }; 34 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/facebook(facebookAuth)/passport.js: -------------------------------------------------------------------------------- 1 | var passport = require('passport'); 2 | var FacebookStrategy = require('passport-facebook').Strategy; 3 | 4 | exports.setup = function (User, config) { 5 | passport.use(new FacebookStrategy({ 6 | clientID: config.facebook.clientID, 7 | clientSecret: config.facebook.clientSecret, 8 | callbackURL: config.facebook.callbackURL 9 | }, 10 | function(accessToken, refreshToken, profile, done) { 11 | User.findOne({ 12 | 'facebook.id': profile.id 13 | }, 14 | function(err, user) { 15 | if (err) { 16 | return done(err); 17 | } 18 | if (!user) { 19 | user = new User({ 20 | name: profile.displayName, 21 | email: profile.emails[0].value, 22 | role: 'user', 23 | username: profile.username, 24 | provider: 'facebook', 25 | facebook: profile._json 26 | }); 27 | user.save(function(err) { 28 | if (err) return done(err); 29 | done(err, user); 30 | }); 31 | } else { 32 | return done(err, user); 33 | } 34 | }) 35 | } 36 | )); 37 | }; 38 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/signup/signup.controller(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .controller('SignupCtrl', function ($scope, Auth, $location<% if (filters.oauth) { %>, $window<% } %>) { 5 | $scope.user = {}; 6 | $scope.errors = {}; 7 | 8 | $scope.register = function(form) { 9 | $scope.submitted = true; 10 | 11 | if(form.$valid) { 12 | Auth.createUser({ 13 | name: $scope.user.name, 14 | email: $scope.user.email, 15 | password: $scope.user.password 16 | }) 17 | .then( function() { 18 | // Account created, redirect to home 19 | $location.path('/'); 20 | }) 21 | .catch( function(err) { 22 | err = err.data; 23 | $scope.errors = {}; 24 | 25 | // Update validity of form fields that match the sql errors 26 | angular.forEach(err.errors, function(error, field) { 27 | form[field].$setValidity('sql', false); 28 | $scope.errors[field] = error.message; 29 | }); 30 | }); 31 | } 32 | }; 33 | <% if(filters.oauth) {%> 34 | $scope.loginOauth = function(provider) { 35 | $window.location.href = '/auth/' + provider; 36 | };<% } %> 37 | }); 38 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/account(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | <% if(filters.ngroute) { %>.config(function ($routeProvider) { 5 | $routeProvider 6 | .when('/login', { 7 | templateUrl: 'app/account/login/login.html', 8 | controller: 'LoginCtrl' 9 | }) 10 | .when('/signup', { 11 | templateUrl: 'app/account/signup/signup.html', 12 | controller: 'SignupCtrl' 13 | }) 14 | .when('/settings', { 15 | templateUrl: 'app/account/settings/settings.html', 16 | controller: 'SettingsCtrl', 17 | authenticate: true 18 | }); 19 | });<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider) { 20 | $stateProvider 21 | .state('login', { 22 | url: '/login', 23 | templateUrl: 'app/account/login/login.html', 24 | controller: 'LoginCtrl' 25 | }) 26 | .state('signup', { 27 | url: '/signup', 28 | templateUrl: 'app/account/signup/signup.html', 29 | controller: 'SignupCtrl' 30 | }) 31 | .state('settings', { 32 | url: '/settings', 33 | templateUrl: 'app/account/settings/settings.html', 34 | controller: 'SettingsCtrl', 35 | authenticate: true 36 | }); 37 | });<% } %> -------------------------------------------------------------------------------- /app/templates/client/app/main/main(jade).jade: -------------------------------------------------------------------------------- 1 | div(ng-include='"components/navbar/navbar.html"') 2 | 3 | header#banner.hero-unit 4 | .container 5 | h1 'Allo, 'Allo! 6 | p.lead Kick-start your next web app with Angular Fullstack 7 | img(src='assets/images/yeoman.png', alt='I\'m Yeoman') 8 | 9 | .container 10 | .row 11 | .col-lg-12 12 | h1.page-header Features: 13 | ul.nav.nav-tabs.nav-stacked.col-md-4.col-lg-4.col-sm-6(ng-repeat='thing in awesomeThings') 14 | li 15 | a(href='#', tooltip='{{thing.info}}') 16 | | {{thing.name}}<% if(filters.socketio) { %> 17 | button.close(type='button', ng-click='deleteThing(thing)') ×<% } %><% if(filters.socketio) { %> 18 | 19 | form.thing-form 20 | label Syncs in realtime across clients 21 | p.input-group 22 | input.form-control(type='text', placeholder='Add a new thing here.', ng-model='newThing') 23 | span.input-group-btn 24 | button.btn.btn-primary(type='submit', ng-click='addThing()') Add New<% } %> 25 | 26 | footer.footer 27 | .container 28 | p 29 | | Angular Fullstack v<%= pkg.version %> 30 | = ' | ' 31 | a(href='https://twitter.com/tyhenkel') @tyhenkel 32 | = ' | ' 33 | a(href='https://github.com/tashrafy/generator-sql-fullstack/issues?state=open') Issues 34 | -------------------------------------------------------------------------------- /test/fixtures/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-sql-fullstack": { 3 | "insertRoutes": true, 4 | "registerRoutesFile": "server/routes.js", 5 | "routesNeedle": "// Insert routes below", 6 | "routesBase": "/api/", 7 | "pluralizeRoutes": true, 8 | "insertSockets": true, 9 | "registerSocketsFile": "server/config/socketio.js", 10 | "socketsNeedle": "// Insert sockets below", 11 | "filters": { 12 | "js": true, 13 | "html": true, 14 | "sass": true, 15 | "uirouter": true, 16 | "bootstrap": true, 17 | "uibootstrap": true, 18 | "socketio": true, 19 | "pgsql": true, 20 | "sql": true, 21 | "auth": true 22 | } 23 | }, 24 | "generator-ng-component": { 25 | "routeDirectory": "client/app/", 26 | "directiveDirectory": "client/app/", 27 | "filterDirectory": "client/app/", 28 | "serviceDirectory": "client/app/", 29 | "basePath": "client", 30 | "moduleName": "", 31 | "filters": [ 32 | "uirouter" 33 | ], 34 | "extensions": [ 35 | "js", 36 | "html", 37 | "scss" 38 | ], 39 | "directiveSimpleTemplates": "", 40 | "directiveComplexTemplates": "", 41 | "filterTemplates": "", 42 | "serviceTemplates": "", 43 | "factoryTemplates": "", 44 | "controllerTemplates": "", 45 | "decoratorTemplates": "", 46 | "providerTemplates": "", 47 | "routeTemplates": "" 48 | } 49 | } -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(less).less: -------------------------------------------------------------------------------- 1 | <% if(filters.bootstrap) { %>// Colors 2 | // -------------------------------------------------- 3 | 4 | @btnText: #fff; 5 | @btnTextAlt: #000;<% if (filters.oauth) { %> 6 | <% if (filters.facebookAuth) { %> 7 | @btnFacebookBackground: #3B5998; 8 | @btnFacebookBackgroundHighlight: #133783;<% } if (filters.twitterAuth) { %> 9 | @btnTwitterBackground: #2daddc; 10 | @btnTwitterBackgroundHighlight: #0271bf;<% } if (filters.googleAuth) { %> 11 | @btnGooglePlusBackground: #dd4b39; 12 | @btnGooglePlusBackgroundHighlight: #c53727;<% } %> 13 | @btnGithubBackground: #fafafa; 14 | @btnGithubBackgroundHighlight: #ccc; 15 | 16 | // Social buttons 17 | // -------------------------------------------------- 18 | <% if (filters.facebookAuth) { %> 19 | .btn-facebook { 20 | .button-variant(@btnText; @btnFacebookBackgroundHighlight; @btnFacebookBackgroundHighlight); 21 | }<% } if (filters.twitterAuth) { %> 22 | .btn-twitter { 23 | .button-variant(@btnText; @btnTwitterBackground; @btnTwitterBackgroundHighlight); 24 | }<% } if (filters.googleAuth) { %> 25 | .btn-google-plus { 26 | .button-variant(@btnText; @btnGooglePlusBackground; @btnGooglePlusBackgroundHighlight); 27 | }<% } %> 28 | .btn-github { 29 | .button-variant(@btnTextAlt; @btnGithubBackground; @btnGithubBackgroundHighlight); 30 | }<% } %><% } %> 31 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(sass).scss: -------------------------------------------------------------------------------- 1 | <% if(filters.bootstrap) { %>// Colors 2 | // -------------------------------------------------- 3 | 4 | $btnText: #fff; 5 | $btnTextAlt: #000;<% if (filters.oauth) { %> 6 | <% if (filters.facebookAuth) { %> 7 | $btnFacebookBackground: #3B5998; 8 | $btnFacebookBackgroundHighlight: #133783;<% } if (filters.twitterAuth) { %> 9 | $btnTwitterBackground: #2daddc; 10 | $btnTwitterBackgroundHighlight: #0271bf;<% } if (filters.googleAuth) { %> 11 | $btnGooglePlusBackground: #dd4b39; 12 | $btnGooglePlusBackgroundHighlight: #c53727;<% } %> 13 | $btnGithubBackground: #fafafa; 14 | $btnGithubBackgroundHighlight: #ccc; 15 | 16 | // Social buttons 17 | // -------------------------------------------------- 18 | <% if (filters.facebookAuth) { %> 19 | .btn-facebook { 20 | @include button-variant($btnText, $btnFacebookBackgroundHighlight, $btnFacebookBackgroundHighlight); 21 | }<% } if (filters.twitterAuth) { %> 22 | .btn-twitter { 23 | @include button-variant($btnText, $btnTwitterBackground, $btnTwitterBackgroundHighlight); 24 | }<% } if (filters.googleAuth) { %> 25 | .btn-google-plus { 26 | @include button-variant($btnText, $btnGooglePlusBackground, $btnGooglePlusBackgroundHighlight); 27 | }<% } %> 28 | .btn-github { 29 | @include button-variant($btnTextAlt, $btnGithubBackground, $btnGithubBackgroundHighlight); 30 | }<% } %><% } %> 31 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/settings/settings(html).html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |

Change Password

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

17 | {{ errors.other }} 18 |

19 |
20 | 21 |
22 | 23 | 24 | 27 |

29 | Password must be at least 3 characters. 30 |

31 |
32 | 33 |

{{ message }}

34 | 35 | 36 |
37 |
38 |
39 |
40 | -------------------------------------------------------------------------------- /app/templates/client/components/navbar/navbar(jade).jade: -------------------------------------------------------------------------------- 1 | div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarCtrl') 2 | div.container 3 | div.navbar-header 4 | button.navbar-toggle(type='button', ng-click='isCollapsed = !isCollapsed') 5 | span.sr-only Toggle navigation 6 | span.icon-bar 7 | span.icon-bar 8 | span.icon-bar 9 | a.navbar-brand(href='/') <%= _.slugify(_.humanize(appname)) %> 10 | 11 | div#navbar-main.navbar-collapse.collapse(collapse='isCollapsed') 12 | ul.nav.navbar-nav 13 | li(ng-repeat='item in menu', ng-class='{active: isActive(item.link)}') 14 | a(ng-href='{{item.link}}') {{item.title}}<% if(filters.auth) { %> 15 | 16 | li(ng-show='isAdmin()', ng-class='{active: isActive("/admin")}') 17 | a(href='/admin') Admin<% } %><% if(filters.auth) { %> 18 | 19 | ul.nav.navbar-nav.navbar-right 20 | li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/signup")}') 21 | a(href='/signup') Sign up 22 | 23 | li(ng-hide='isLoggedIn()', ng-class='{active: isActive("/login")}') 24 | a(href='/login') Login 25 | 26 | li(ng-show='isLoggedIn()') 27 | p.navbar-text Hello {{ getCurrentUser().name }} 28 | 29 | li(ng-show='isLoggedIn()', ng-class='{active: isActive("/settings")}') 30 | a(href='/settings') 31 | span.glyphicon.glyphicon-cog 32 | 33 | li(ng-show='isLoggedIn()', ng-class='{active: isActive("/logout")}') 34 | a(href='', ng-click='logout()') Logout<% } %> -------------------------------------------------------------------------------- /app/templates/client/app/main/main(html).html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 10 | 11 |
12 |
13 |
14 |

Features:

15 | 18 |
19 |
<% if(filters.socketio) { %> 20 | 21 |
22 | 23 |

24 | 25 | 26 | 27 | 28 |

29 |
<% } %> 30 |
31 | 32 | 39 | -------------------------------------------------------------------------------- /app/templates/client/app/app(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>', [<%= angularModules %>] 4 | <% if(filters.ngroute) { %>.config ($routeProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) -> 5 | $routeProvider 6 | .otherwise 7 | redirectTo: '/' 8 | 9 | $locationProvider.html5Mode true<% if(filters.auth) { %> 10 | $httpProvider.interceptors.push 'authInterceptor'<% } %> 11 | <% } %><% if(filters.uirouter) { %>.config ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) -> 12 | $urlRouterProvider 13 | .otherwise '/' 14 | 15 | $locationProvider.html5Mode true<% if(filters.auth) { %> 16 | $httpProvider.interceptors.push 'authInterceptor'<% } %> 17 | <% } %><% if(filters.auth) { %> 18 | .factory 'authInterceptor', ($rootScope, $q, $cookieStore, $location) -> 19 | # Add authorization token to headers 20 | request: (config) -> 21 | config.headers = config.headers or {} 22 | config.headers.Authorization = 'Bearer ' + $cookieStore.get 'token' if $cookieStore.get 'token' 23 | config 24 | 25 | # Intercept 401s and redirect you to login 26 | responseError: (response) -> 27 | if response.status is 401 28 | $location.path '/login' 29 | # remove any stale tokens 30 | $cookieStore.remove 'token' 31 | 32 | $q.reject response 33 | 34 | .run ($rootScope, $location, Auth) -> 35 | # Redirect to login if route requires auth and you're not logged in 36 | $rootScope.$on <% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, (event, next) -> 37 | Auth.isLoggedInAsync (loggedIn) -> 38 | $location.path "/login" if next.authenticate and not loggedIn 39 | <% } %> -------------------------------------------------------------------------------- /app/templates/client/components/navbar/navbar(html).html: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /app/templates/client/app/app(css).css: -------------------------------------------------------------------------------- 1 | <% if(filters.bootstrap) { %> 2 | /** 3 | * Bootstrap Fonts 4 | */ 5 | 6 | @font-face { 7 | font-family: 'Glyphicons Halflings'; 8 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot'); 9 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), 10 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), 11 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), 12 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 13 | }<% } %> 14 | 15 | /** 16 | *Font Awesome Fonts 17 | */ 18 | 19 | @font-face { 20 | font-family: 'FontAwesome'; 21 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0'); 22 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), 23 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), 24 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), 25 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); 26 | font-weight: normal; 27 | font-style: normal; 28 | } 29 | 30 | /** 31 | * App-wide Styles 32 | */ 33 | 34 | .browsehappy { 35 | margin: 0.2em 0; 36 | background: #ccc; 37 | color: #000; 38 | padding: 0.2em 0; 39 | } 40 | <% if (!filters.bootstrap) { %> 41 | /* Responsive: Portrait tablets and up */ 42 | @media screen and (min-width: 768px) { 43 | .container { 44 | max-width: 730px; 45 | } 46 | }<% } %> -------------------------------------------------------------------------------- /app/templates/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration 2 | // https://github.com/angular/protractor/blob/master/referenceConf.js 3 | 4 | 'use strict'; 5 | 6 | exports.config = { 7 | // The timeout for each script run on the browser. This should be longer 8 | // than the maximum time your application needs to stabilize between tasks. 9 | allScriptsTimeout: 110000, 10 | 11 | // A base URL for your application under test. Calls to protractor.get() 12 | // with relative paths will be prepended with this. 13 | baseUrl: 'http://localhost:' + (process.env.PORT || '9000'), 14 | 15 | // If true, only chromedriver will be started, not a standalone selenium. 16 | // Tests for browsers other than chrome will not run. 17 | chromeOnly: true, 18 | 19 | // list of files / patterns to load in the browser 20 | specs: [ 21 | 'e2e/**/*.spec.js' 22 | ], 23 | 24 | // Patterns to exclude. 25 | exclude: [], 26 | 27 | // ----- Capabilities to be passed to the webdriver instance ---- 28 | // 29 | // For a full list of available capabilities, see 30 | // https://code.google.com/p/selenium/wiki/DesiredCapabilities 31 | // and 32 | // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js 33 | capabilities: { 34 | 'browserName': 'chrome' 35 | }, 36 | 37 | // ----- The test framework ----- 38 | // 39 | // Jasmine and Cucumber are fully supported as a test and assertion framework. 40 | // Mocha has limited beta support. You will need to include your own 41 | // assertion framework if working with mocha. 42 | framework: 'jasmine', 43 | 44 | // ----- Options to be passed to minijasminenode ----- 45 | // 46 | // See the full list at https://github.com/juliemr/minijasminenode 47 | jasmineNodeOpts: { 48 | defaultTimeoutInterval: 30000 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /app/templates/server/config/socketio(socketio).js: -------------------------------------------------------------------------------- 1 | /** 2 | * Socket.io configuration 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var config = require('./environment'); 8 | 9 | // When the user disconnects.. perform this 10 | function onDisconnect(socket) { 11 | } 12 | 13 | // When the user connects.. perform this 14 | function onConnect(socket) { 15 | // When the client emits 'info', this listens and executes 16 | socket.on('info', function (data) { 17 | console.info('[%s] %s', socket.address, JSON.stringify(data, null, 2)); 18 | }); 19 | 20 | // Insert sockets below 21 | require('../api/thing/thing.socket').register(socket); 22 | } 23 | 24 | module.exports = function (socketio) { 25 | // socket.io (v1.x.x) is powered by debug. 26 | // In order to see all the debug output, set DEBUG (in server/config/local.env.js) to including the desired scope. 27 | // 28 | // ex: DEBUG: "http*,socket.io:socket" 29 | 30 | // We can authenticate socket.io users and access their token through socket.handshake.decoded_token 31 | // 32 | // 1. You will need to send the token in `client/components/socket/socket.service.js` 33 | // 34 | // 2. Require authentication here: 35 | // socketio.use(require('socketio-jwt').authorize({ 36 | // secret: config.secrets.session, 37 | // handshake: true 38 | // })); 39 | 40 | socketio.on('connection', function (socket) { 41 | socket.address = socket.handshake.address !== null ? 42 | socket.handshake.address.address + ':' + socket.handshake.address.port : 43 | process.env.DOMAIN; 44 | 45 | socket.connectedAt = new Date(); 46 | 47 | // Call onDisconnect. 48 | socket.on('disconnect', function () { 49 | onDisconnect(socket); 50 | console.info('[%s] DISCONNECTED', socket.address); 51 | }); 52 | 53 | // Call onConnect. 54 | onConnect(socket); 55 | console.info('[%s] CONNECTED', socket.address); 56 | }); 57 | }; -------------------------------------------------------------------------------- /app/templates/client/app/app(stylus).styl: -------------------------------------------------------------------------------- 1 | @import "font-awesome/css/font-awesome.css" 2 | <% if(filters.bootstrap) { %>@import "bootstrap/dist/css/bootstrap.css" 3 | 4 | // 5 | // Bootstrap Fonts 6 | // 7 | 8 | @font-face 9 | font-family: 'Glyphicons Halflings' 10 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot') 11 | src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), 12 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), 13 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), 14 | url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 15 | <% } %> 16 | // 17 | // Font Awesome Fonts 18 | // 19 | 20 | @font-face 21 | font-family: 'FontAwesome' 22 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0') 23 | src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), 24 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), 25 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), 26 | url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); 27 | font-weight: normal 28 | font-style: normal 29 | 30 | // 31 | // App-wide Styles 32 | // 33 | 34 | .browsehappy 35 | background #ccc 36 | color #000 37 | margin 0.2em 0 38 | padding 0.2em 0 39 | <% if (!filters.bootstrap) { %> 40 | // Responsive: Portrait tablets and up 41 | @media screen and (min-width: 768px) 42 | .container 43 | max-width 730px 44 | <% } %> 45 | // Component styles are injected through grunt 46 | // injector 47 | @import "account/login/login" 48 | @import "admin/admin" 49 | @import "main/main" 50 | // endinjector -------------------------------------------------------------------------------- /app/templates/client/components/socket(socketio)/socket.service(coffee).coffee: -------------------------------------------------------------------------------- 1 | # global io 2 | 3 | 'use strict' 4 | 5 | angular.module '<%= scriptAppName %>' 6 | .factory 'socket', (socketFactory) -> 7 | 8 | # socket.io now auto-configures its connection when we omit a connection url 9 | ioSocket = io '', 10 | # Send auth token on connection, you will need to DI the Auth service above 11 | # 'query': 'token=' + Auth.getToken() 12 | path: '/socket.io-client' 13 | 14 | socket = socketFactory ioSocket: ioSocket 15 | 16 | socket: socket 17 | 18 | ### 19 | Register listeners to sync an array with updates on a model 20 | 21 | Takes the array we want to sync, the model name that socket updates are sent from, 22 | and an optional callback function after new items are updated. 23 | 24 | @param {String} modelName 25 | @param {Array} array 26 | @param {Function} callback 27 | ### 28 | syncUpdates: (modelName, array, callback) -> 29 | 30 | ### 31 | Syncs item creation/updates on 'model:save' 32 | ### 33 | socket.on modelName + ':save', (item) -> 34 | oldItem = _.find array, 35 | _id: item._id 36 | 37 | index = array.indexOf oldItem 38 | event = 'created' 39 | 40 | # replace oldItem if it exists 41 | # otherwise just add item to the collection 42 | if oldItem 43 | array.splice index, 1, item 44 | event = 'updated' 45 | else 46 | array.push item 47 | 48 | callback? event, item, array 49 | 50 | ### 51 | Syncs removed items on 'model:remove' 52 | ### 53 | socket.on modelName + ':remove', (item) -> 54 | event = 'deleted' 55 | _.remove array, 56 | _id: item._id 57 | 58 | callback? event, item, array 59 | 60 | ### 61 | Removes listeners for a models updates on the socket 62 | 63 | @param modelName 64 | ### 65 | unsyncUpdates: (modelName) -> 66 | socket.removeAllListeners modelName + ':save' 67 | socket.removeAllListeners modelName + ':remove' 68 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(jade).jade: -------------------------------------------------------------------------------- 1 | div(ng-include='"components/navbar/navbar.html"') 2 | .container 3 | .row 4 | .col-sm-12 5 | h1 Login 6 | p 7 | | Accounts are reset on server restart from 8 | code server/config/seed.js 9 | | . Default account is 10 | code test@test.com 11 | | / 12 | code test 13 | p 14 | | Admin account is 15 | code admin@admin.com 16 | | / 17 | code admin 18 | 19 | .col-sm-12 20 | form.form(name='form', ng-submit='login(form)', novalidate='') 21 | .form-group 22 | label Email 23 | input.form-control(type='text', name='email', ng-model='user.email') 24 | .form-group 25 | label Password 26 | input.form-control(type='password', name='password', ng-model='user.password') 27 | 28 | .form-group.has-error 29 | p.help-block(ng-show='form.email.$error.required && form.password.$error.required && submitted') 30 | | Please enter your email and password. 31 | p.help-block {{ errors.other }} 32 | 33 | div 34 | button.btn.btn-inverse.btn-lg.btn-login(type='submit') 35 | | Login 36 | = ' ' 37 | a.btn.btn-default.btn-lg.btn-register(href='/signup') 38 | | Register 39 | <% if(filters.oauth) {%> 40 | hr 41 | 42 | div<% if(filters.facebookAuth) {%> 43 | a.btn.btn-facebook(href='', ng-click='loginOauth("facebook")') 44 | i.fa.fa-facebook 45 | | Connect with Facebook 46 | = ' '<% } %><% if(filters.googleAuth) {%> 47 | a.btn.btn-google-plus(href='', ng-click='loginOauth("google")') 48 | i.fa.fa-google-plus 49 | | Connect with Google+ 50 | = ' '<% } %><% if(filters.twitterAuth) {%> 51 | a.btn.btn-twitter(href='', ng-click='loginOauth("twitter")') 52 | i.fa.fa-twitter 53 | | Connect with Twitter<% } %><% } %> 54 | hr 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-sql-fullstack", 3 | "version": "1.0.1", 4 | "description": "Yeoman generator for creating SQL-EAN stack applications, using SQL(e.g. Postgres, MySQL, MariaDB, SQLite, MSSQL), Express, AngularJS, and Node", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "pean", 8 | "sean", 9 | "mssql", 10 | "mariadb", 11 | "mariasql", 12 | "sqlite", 13 | "sqlite3", 14 | "node-sqlite3", 15 | "node-postgres", 16 | "node-mariadb", 17 | "node-mssql", 18 | "sql", 19 | "sql-fullstack", 20 | "postgres", 21 | "angularjs", 22 | "express", 23 | "scaffold", 24 | "fullstack", 25 | "framework", 26 | "component", 27 | "front-end", 28 | "app" 29 | ], 30 | "homepage": "https://github.com/tashrafy/generator-sql-fullstack", 31 | "bugs": "https://github.com/tashrafy/generator-sql-fullstack/issues", 32 | "author": "Taufiqur Ashrafy", 33 | "repository": { 34 | "type": "git", 35 | "url": "git://github.com/tashrafy/generator-sql-fullstack.git" 36 | }, 37 | "scripts": { 38 | "test": "grunt test" 39 | }, 40 | "dependencies": { 41 | "yeoman-generator": "~0.17.0", 42 | "chalk": "~0.4.0", 43 | "wiredep": "~0.4.2", 44 | "generator-ng-component": "~0.0.4" 45 | }, 46 | "peerDependencies": { 47 | "yo": ">=1.2.0" 48 | }, 49 | "devDependencies": { 50 | "chai": "^1.9.1", 51 | "fs-extra": "^0.9.1", 52 | "grunt": "~0.4.1", 53 | "grunt-build-control": "DaftMonk/grunt-build-control", 54 | "grunt-contrib-clean": "^0.6.0", 55 | "grunt-contrib-jshint": "^0.10.0", 56 | "grunt-conventional-changelog": "~1.0.0", 57 | "grunt-mocha-test": "^0.11.0", 58 | "grunt-release": "~0.6.0", 59 | "load-grunt-tasks": "~0.2.0", 60 | "marked": "~0.2.8", 61 | "mocha": "~1.21.0", 62 | "q": "^1.0.1", 63 | "semver": "~2.2.1", 64 | "shelljs": "^0.3.0", 65 | "underscore.string": "^2.3.3" 66 | }, 67 | "engines": { 68 | "node": ">=0.10.0", 69 | "npm": ">=1.2.10" 70 | }, 71 | "licenses": [ 72 | { 73 | "type": "BSD" 74 | } 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /app/templates/server/api/user(auth)/user.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var should = require('should'); 4 | var app = require('../../app'); 5 | var User = require('../').User; 6 | 7 | var user; 8 | 9 | var genUser = function() { 10 | user = User.build({ 11 | provider: 'local', 12 | name: 'Fake User', 13 | email: 'test@example.com', 14 | password: 'password' 15 | }); 16 | return user; 17 | }; 18 | 19 | describe('User Model', function() { 20 | before(function(done) { 21 | genUser(); 22 | done(); 23 | }); 24 | 25 | afterEach(function() { 26 | return User.destroy({ where: {} }); 27 | }); 28 | 29 | it('should begin with no users', function(done) { 30 | return User 31 | .findAll({ where: {} }) 32 | .then(function(users) { 33 | console.log("------------------------------------------------------"); 34 | users.should.have.length(0); 35 | done(); 36 | }) 37 | .catch(function(err){ 38 | console.log(err, '-------------------------------'); 39 | }); 40 | }); 41 | 42 | it('should fail when saving a duplicate user', function(done) { 43 | var newUser = genUser(); 44 | newUser.save().catch(function(err){ 45 | should.exist(err); 46 | }); 47 | }); 48 | 49 | it('should fail when saving without an email', function(done) { 50 | user.email = ''; 51 | user.save() 52 | .catch(function(err){ 53 | should.exist(err); 54 | done(); 55 | }); 56 | }); 57 | 58 | it("should authenticate user if password is valid", function(done) { 59 | User 60 | .create(user) 61 | .then(function(userInstance){ 62 | var check = userInstance.authenticate('password'); 63 | check.should.be.true; // jshint ignore:line 64 | done(); 65 | }); 66 | }); 67 | 68 | it("should not authenticate user if password is invalid", function(done) { 69 | User 70 | .create(user) 71 | .then(function(userInstance){ 72 | var check = userInstance.authenticate('blah'); 73 | check.should.not.be.true; // jshint ignore:line 74 | done(); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /app/templates/client/app/app(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>', [<%= angularModules %>]) 4 | <% if(filters.ngroute) { %>.config(function ($routeProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { 5 | $routeProvider 6 | .otherwise({ 7 | redirectTo: '/' 8 | }); 9 | 10 | $locationProvider.html5Mode(true);<% if(filters.auth) { %> 11 | $httpProvider.interceptors.push('authInterceptor');<% } %> 12 | })<% } %><% if(filters.uirouter) { %>.config(function ($stateProvider, $urlRouterProvider, $locationProvider<% if(filters.auth) { %>, $httpProvider<% } %>) { 13 | $urlRouterProvider 14 | .otherwise('/'); 15 | 16 | $locationProvider.html5Mode(true);<% if(filters.auth) { %> 17 | $httpProvider.interceptors.push('authInterceptor');<% } %> 18 | })<% } %><% if(filters.auth) { %> 19 | 20 | .factory('authInterceptor', function ($rootScope, $q, $cookieStore, $location) { 21 | return { 22 | // Add authorization token to headers 23 | request: function (config) { 24 | config.headers = config.headers || {}; 25 | if ($cookieStore.get('token')) { 26 | config.headers.Authorization = 'Bearer ' + $cookieStore.get('token'); 27 | } 28 | return config; 29 | }, 30 | 31 | // Intercept 401s and redirect you to login 32 | responseError: function(response) { 33 | if(response.status === 401) { 34 | $location.path('/login'); 35 | // remove any stale tokens 36 | $cookieStore.remove('token'); 37 | return $q.reject(response); 38 | } 39 | else { 40 | return $q.reject(response); 41 | } 42 | } 43 | }; 44 | }) 45 | 46 | .run(function ($rootScope, $location, Auth) { 47 | // Redirect to login if route requires auth and you're not logged in 48 | $rootScope.$on(<% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, function (event, next) { 49 | Auth.isLoggedInAsync(function(loggedIn) { 50 | if (next.authenticate && !loggedIn) { 51 | $location.path('/login'); 52 | } 53 | }); 54 | }); 55 | })<% } %>; -------------------------------------------------------------------------------- /app/templates/server/config/seed(sql).js: -------------------------------------------------------------------------------- 1 | /** 2 | * Populate DB with sample data on server start 3 | * to disable, edit config/environment/index.js, and set `seedDB: false` 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var Thing = require('../api').Thing; 9 | <% if (filters.auth) { %>var User = require('../api').User;<% } %> 10 | 11 | Thing 12 | .sync() 13 | .then(function() { 14 | return Thing.destroy({ where: {} }); 15 | }) 16 | .then(function() { 17 | Thing.bulkCreate([{ 18 | name: 'Development Tools', 19 | info: 'Integration with popular tools such as Bower, Grunt, Babel, Karma, ' + 20 | 'Mocha, JSHint, Node Inspector, Livereload, Protractor, Jade, ' + 21 | 'Stylus, Sass, and Less.' 22 | }, { 23 | name: 'Server and Client integration', 24 | info: 'Built with a powerful and fun stack: MongoDB, Express, ' + 25 | 'AngularJS, and Node.' 26 | }, { 27 | name: 'Smart Build System', 28 | info: 'Build system ignores `spec` files, allowing you to keep ' + 29 | 'tests alongside code. Automatic injection of scripts and ' + 30 | 'styles into your index.html' 31 | }, { 32 | name: 'Modular Structure', 33 | info: 'Best practice client and server structures allow for more ' + 34 | 'code reusability and maximum scalability' 35 | }, { 36 | name: 'Optimized Build', 37 | info: 'Build process packs up your templates as a single JavaScript ' + 38 | 'payload, minifies your scripts/css/images, and rewrites asset ' + 39 | 'names for caching.' 40 | }, { 41 | name: 'Deployment Ready', 42 | info: 'Easily deploy your app to Heroku or Openshift with the heroku ' + 43 | 'and openshift subgenerators' 44 | }]); 45 | });<% if (filters.auth) { %> 46 | 47 | User.sync() 48 | .then(function() { 49 | return User.destroy({ where: {} }); 50 | }) 51 | .then(function() { 52 | User.bulkCreate([{ 53 | username: 'User', 54 | email: 'test@example.com', 55 | password: 'test', 56 | provider: 'local' 57 | }, { 58 | username: ' AdminUser', 59 | email: 'admin@example.com', 60 | provider: 'local', 61 | password: 'admin' 62 | }]) 63 | .then(function() { 64 | console.log('finished populating users'); 65 | }); 66 | }); 67 | <% } %> 68 | -------------------------------------------------------------------------------- /endpoint/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var yeoman = require('yeoman-generator'); 4 | var util = require('util'); 5 | var ngUtil = require('../util'); 6 | var ScriptBase = require('../script-base.js'); 7 | 8 | var Generator = module.exports = function Generator() { 9 | ScriptBase.apply(this, arguments); 10 | }; 11 | 12 | util.inherits(Generator, ScriptBase); 13 | 14 | Generator.prototype.askFor = function askFor() { 15 | var done = this.async(); 16 | var name = this.name; 17 | 18 | var base = this.config.get('routesBase') || '/api/'; 19 | if(base.charAt(base.length-1) !== '/') { 20 | base = base + '/'; 21 | } 22 | 23 | // pluralization defaults to true for backwards compat 24 | if (this.config.get('pluralizeRoutes') !== false) { 25 | name = name + 's'; 26 | } 27 | 28 | var prompts = [ 29 | { 30 | name: 'route', 31 | message: 'What will the url of your endpoint be?', 32 | default: base + name 33 | } 34 | ]; 35 | 36 | this.prompt(prompts, function (props) { 37 | if(props.route.charAt(0) !== '/') { 38 | props.route = '/' + props.route; 39 | } 40 | 41 | this.route = props.route; 42 | done(); 43 | }.bind(this)); 44 | }; 45 | 46 | Generator.prototype.registerEndpoint = function registerEndpoint() { 47 | if(this.config.get('insertRoutes')) { 48 | var routeConfig = { 49 | file: this.config.get('registerRoutesFile'), 50 | needle: this.config.get('routesNeedle'), 51 | splicable: [ 52 | "app.use(\'" + this.route +"\', require(\'./api/" + this.name + "\'));" 53 | ] 54 | }; 55 | ngUtil.rewriteFile(routeConfig); 56 | } 57 | 58 | if (this.filters.socketio) { 59 | if(this.config.get('insertSockets')) { 60 | var socketConfig = { 61 | file: this.config.get('registerSocketsFile'), 62 | needle: this.config.get('socketsNeedle'), 63 | splicable: [ 64 | "require(\'../api/" + this.name + '/' + this.name + ".socket\').register(socket);" 65 | ] 66 | }; 67 | ngUtil.rewriteFile(socketConfig); 68 | } 69 | } 70 | }; 71 | 72 | Generator.prototype.createFiles = function createFiles() { 73 | var dest = this.config.get('endpointDirectory') || 'server/api/' + this.name; 74 | this.sourceRoot(path.join(__dirname, './templates')); 75 | ngUtil.processDirectory(this, '.', dest); 76 | }; 77 | -------------------------------------------------------------------------------- /app/templates/client/components/socket(socketio)/socket.service.js: -------------------------------------------------------------------------------- 1 | /* global io */ 2 | 'use strict'; 3 | 4 | angular.module('<%= scriptAppName %>') 5 | .factory('socket', function(socketFactory) { 6 | 7 | // socket.io now auto-configures its connection when we ommit a connection url 8 | var ioSocket = io('', { 9 | // Send auth token on connection, you will need to DI the Auth service above 10 | // 'query': 'token=' + Auth.getToken() 11 | path: '/socket.io-client' 12 | }); 13 | 14 | var socket = socketFactory({ 15 | ioSocket: ioSocket 16 | }); 17 | 18 | return { 19 | socket: socket, 20 | 21 | /** 22 | * Register listeners to sync an array with updates on a model 23 | * 24 | * Takes the array we want to sync, the model name that socket updates are sent from, 25 | * and an optional callback function after new items are updated. 26 | * 27 | * @param {String} modelName 28 | * @param {Array} array 29 | * @param {Function} cb 30 | */ 31 | syncUpdates: function (modelName, array, cb) { 32 | cb = cb || angular.noop; 33 | 34 | /** 35 | * Syncs item creation/updates on 'model:save' 36 | */ 37 | socket.on(modelName + ':save', function (item) { 38 | var oldItem = _.find(array, {_id: item._id}); 39 | var index = array.indexOf(oldItem); 40 | var event = 'created'; 41 | 42 | // replace oldItem if it exists 43 | // otherwise just add item to the collection 44 | if (oldItem) { 45 | array.splice(index, 1, item); 46 | event = 'updated'; 47 | } else { 48 | array.push(item); 49 | } 50 | 51 | cb(event, item, array); 52 | }); 53 | 54 | /** 55 | * Syncs removed items on 'model:remove' 56 | */ 57 | socket.on(modelName + ':remove', function (item) { 58 | var event = 'deleted'; 59 | _.remove(array, {_id: item._id}); 60 | cb(event, item, array); 61 | }); 62 | }, 63 | 64 | /** 65 | * Removes listeners for a models updates on the socket 66 | * 67 | * @param modelName 68 | */ 69 | unsyncUpdates: function (modelName) { 70 | socket.removeAllListeners(modelName + ':save'); 71 | socket.removeAllListeners(modelName + ':remove'); 72 | } 73 | }; 74 | }); 75 | -------------------------------------------------------------------------------- /app/templates/server/config/express.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Express configuration 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var express = require('express'); 8 | var favicon = require('serve-favicon'); 9 | var morgan = require('morgan'); 10 | var compression = require('compression'); 11 | var bodyParser = require('body-parser'); 12 | var methodOverride = require('method-override'); 13 | var cookieParser = require('cookie-parser'); 14 | var errorHandler = require('errorhandler'); 15 | var path = require('path'); 16 | var config = require('./environment');<% if (filters.auth) { %> 17 | var passport = require('passport');<% } %><% if (filters.twitterAuth) { %> 18 | var session = require('express-session'); 19 | var pgStore = require('connect-pg-simple')(session); <% } %> 20 | 21 | module.exports = function(app) { 22 | var env = app.get('env'); 23 | 24 | app.set('views', config.root + '/server/views');<% if (filters.html) { %> 25 | app.engine('html', require('ejs').renderFile); 26 | app.set('view engine', 'html');<% } %><% if (filters.jade) { %> 27 | app.set('view engine', 'jade');<% } %> 28 | app.set('models', require('../api')); 29 | app.use(compression()); 30 | app.use(bodyParser.urlencoded({ extended: false })); 31 | app.use(bodyParser.json()); 32 | app.use(methodOverride()); 33 | app.use(cookieParser()); 34 | <% if (filters.auth) { %>app.use(passport.initialize());<% } %><% if (filters.twitterAuth) { %> 35 | 36 | // Persist sessions with pgStore 37 | // We need to enable sessions for passport twitter because its an oauth 1.0 strategy 38 | app.use(session({ 39 | secret: config.secrets.session, 40 | resave: true, 41 | saveUninitialized: true, 42 | store: new pgStore(), 43 | cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 } // 30 days 44 | })); 45 | <% } %> 46 | if ('production' === env) { 47 | app.use(favicon(path.join(config.root, 'public', 'favicon.ico'))); 48 | app.use(express.static(path.join(config.root, 'public'))); 49 | app.set('appPath', path.join(config.root, 'public')); 50 | app.use(morgan('dev')); 51 | } 52 | 53 | if ('development' === env || 'test' === env) { 54 | app.use(require('connect-livereload')()); 55 | app.use(express.static(path.join(config.root, '.tmp'))); 56 | app.use(express.static(path.join(config.root, 'client'))); 57 | app.set('appPath', path.join(config.root, 'client')); 58 | app.use(morgan('dev')); 59 | app.use(errorHandler()); // Error handler - has to be last 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal.service(coffee).coffee: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | angular.module '<%= scriptAppName %>' 4 | .factory 'Modal', ($rootScope, $modal) -> 5 | 6 | ### 7 | Opens a modal 8 | @param {Object} scope - an object to be merged with modal's scope 9 | @param {String} modalClass - (optional) class(es) to be applied to the modal 10 | @return {Object} - the instance $modal.open() returns 11 | ### 12 | openModal = (scope, modalClass) -> 13 | modalScope = $rootScope.$new() 14 | scope = scope or {} 15 | modalClass = modalClass or 'modal-default' 16 | angular.extend modalScope, scope 17 | $modal.open 18 | templateUrl: 'components/modal/modal.html' 19 | windowClass: modalClass 20 | scope: modalScope 21 | 22 | 23 | # Public API here 24 | 25 | # Confirmation modals 26 | confirm: 27 | 28 | ### 29 | Create a function to open a delete confirmation modal (ex. ng-click='myModalFn(name, arg1, arg2...)') 30 | @param {Function} del - callback, ran when delete is confirmed 31 | @return {Function} - the function to open the modal (ex. myModalFn) 32 | ### 33 | delete: (del) -> 34 | del = del or angular.noop 35 | 36 | ### 37 | Open a delete confirmation modal 38 | @param {String} name - name or info to show on modal 39 | @param {All} - any additional args are passed staight to del callback 40 | ### 41 | -> 42 | args = Array::slice.call arguments 43 | name = args.shift() 44 | deleteModal = undefined 45 | deleteModal = openModal( 46 | modal: 47 | dismissable: true 48 | title: 'Confirm Delete' 49 | html: '

Are you sure you want to delete ' + name + ' ?

' 50 | buttons: [ 51 | { 52 | classes: 'btn-danger' 53 | text: 'Delete' 54 | click: (e) -> 55 | deleteModal.close e 56 | return 57 | } 58 | { 59 | classes: 'btn-default' 60 | text: 'Cancel' 61 | click: (e) -> 62 | deleteModal.dismiss e 63 | return 64 | } 65 | ] 66 | , 'modal-danger') 67 | deleteModal.result.then (event) -> 68 | del.apply event, args 69 | return 70 | 71 | return 72 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/login/login(html).html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |

Login

7 |

Accounts are reset on server restart from server/config/seed.js. Default account is test@test.com / test

8 |

Admin account is admin@admin.com / admin

9 |
10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | 23 |
24 | 25 |
26 |

27 | Please enter your email and password. 28 |

29 |

30 | Please enter a valid email. 31 |

32 | 33 |

{{ errors.other }}

34 |
35 | 36 |
37 | 40 | 41 | Register 42 | 43 |
44 | <% if(filters.oauth) {%> 45 |
46 |
<% if(filters.facebookAuth) {%> 47 | 48 | Connect with Facebook 49 | <% } %><% if(filters.googleAuth) {%> 50 | 51 | Connect with Google+ 52 | <% } %><% if(filters.twitterAuth) {%> 53 | 54 | Connect with Twitter 55 | <% } %> 56 |
<% } %> 57 |
58 |
59 |
60 |
61 |
62 | -------------------------------------------------------------------------------- /app/templates/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | <% if(filters.ngroute) { %>
<% } %><% if(filters.uirouter) { %>
<% } %> 31 | 32 | 33 | 42 | 43 | 47 | 48 | 49 | <% if(filters.socketio) { %> 50 | <% } %> 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /endpoint/templates/name.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash');<% if (filters.sql) { %> 4 | 5 | function <%= classedName %>(req){ 6 | return req.app.get('models').<%= classedName %>; 7 | }<% } %> 8 | 9 | // Get list of <%= name %>s 10 | exports.index = function(req, res) {<% if (!filters.sql) { %> 11 | res.json([]);<% } %><% if (filters.sql) { %> 12 | <%= classedName %>(req) 13 | .findAll({ where: {} }) 14 | .then(function (<%= name %>s) { 15 | return res.status(200).json(<%= name %>s); 16 | }) 17 | .catch(function (err){ 18 | if(err) { return handleError(res, err); } 19 | });<% } %> 20 | };<% if (filters.sql) { %> 21 | 22 | // Get a single <%= name %> 23 | exports.show = function(req, res) { 24 | <%= classedName %> 25 | .findById(req.params.id) 26 | .then(function (<%= name %>) { 27 | if(!<%= name %>) { return res.status(404).send('Not Found'); } 28 | return res.json(<%= name %>); 29 | }) 30 | .catch(function (err){ 31 | if(err) { return handleError(res, err); } 32 | }); 33 | }; 34 | 35 | // Creates a new <%= name %> in the DB. 36 | exports.create = function(req, res) { 37 | <%= classedName %> 38 | .create(req.body) 39 | .then(function (<%= name %>) { 40 | return res.status(201).json(<%= name %>); 41 | }) 42 | .catch(function (err){ 43 | if(err) { return handleError(res, err); } 44 | }); 45 | }; 46 | 47 | // Updates an existing <%= name %> in the DB. 48 | exports.update = function(req, res) { 49 | if(req.body._id) { delete req.body._id; } 50 | <%= classedName %> 51 | .findById(req.params.id) 52 | .then(function (<%= name %>) { 53 | if(!<%= name %>) { return res.status(404).send('Not Found'); } 54 | var updated = _.merge(<%= name %>, req.body); 55 | updated.save(function (err) { 56 | if (err) { return handleError(res, err); } 57 | return res.status(200).json(<%= name %>); 58 | }); 59 | }) 60 | .catch(function (err){ 61 | if (err) { return handleError(res, err); } 62 | }); 63 | }; 64 | 65 | // Deletes a <%= name %> from the DB. 66 | exports.destroy = function(req, res) { 67 | <%= classedName %> 68 | .findById(req.params.id) 69 | .then(function (<%= name %>) { 70 | if(!<%= name %>) { return res.status(404).send('Not Found'); } 71 | <%= name %>.destroy(function(err) { 72 | if(err) { return handleError(res, err); } 73 | return res.status(204).send('No Content'); 74 | }); 75 | }) 76 | .catch(function (err){ 77 | if(err) { return handleError(res, err); } 78 | }); 79 | }; 80 | 81 | function handleError(res, err) { 82 | return res.status(500).send(err); 83 | }<% } %> 84 | -------------------------------------------------------------------------------- /app/templates/client/app/account(auth)/signup/signup(jade).jade: -------------------------------------------------------------------------------- 1 | div(ng-include='"components/navbar/navbar.html"') 2 | .container 3 | .row 4 | .col-sm-12 5 | h1 Sign up 6 | .col-sm-12 7 | form.form(name='form', ng-submit='register(form)', novalidate='') 8 | .form-group(ng-class='{ "has-success": form.name.$valid && submitted,\ 9 | "has-error": form.name.$invalid && submitted }') 10 | label Name 11 | input.form-control(type='text', name='name', ng-model='user.name', required='') 12 | p.help-block(ng-show='form.name.$error.required && submitted') 13 | | A name is required 14 | 15 | .form-group(ng-class='{ "has-success": form.email.$valid && submitted,\ 16 | "has-error": form.email.$invalid && submitted }') 17 | label Email 18 | input.form-control(type='email', name='email', ng-model='user.email', required='', sql-error='') 19 | p.help-block(ng-show='form.email.$error.email && submitted') 20 | | Doesn't look like a valid email. 21 | p.help-block(ng-show='form.email.$error.required && submitted') 22 | | What's your email address? 23 | p.help-block(ng-show='form.email.$error.sql') 24 | | {{ errors.email }} 25 | 26 | .form-group(ng-class='{ "has-success": form.password.$valid && submitted,\ 27 | "has-error": form.password.$invalid && submitted }') 28 | label Password 29 | input.form-control(type='password', name='password', ng-model='user.password', ng-minlength='3', required='', sql-error='') 30 | p.help-block(ng-show='(form.password.$error.minlength || form.password.$error.required) && submitted') 31 | | Password must be at least 3 characters. 32 | p.help-block(ng-show='form.password.$error.sql') 33 | | {{ errors.password }} 34 | 35 | div 36 | button.btn.btn-inverse.btn-lg.btn-login(type='submit') 37 | | Sign up 38 | = ' ' 39 | a.btn.btn-default.btn-lg.btn-register(href='/login') 40 | | Login 41 | 42 | <% if(filters.oauth) {%> 43 | hr 44 | 45 | div<% if(filters.facebookAuth) {%> 46 | a.btn.btn-facebook(href='', ng-click='loginOauth("facebook")') 47 | i.fa.fa-facebook 48 | | Connect with Facebook 49 | = ' '<% } %><% if(filters.googleAuth) {%> 50 | a.btn.btn-google-plus(href='', ng-click='loginOauth("google")') 51 | i.fa.fa-google-plus 52 | | Connect with Google+ 53 | = ' '<% } %><% if(filters.twitterAuth) {%> 54 | a.btn.btn-twitter(href='', ng-click='loginOauth("twitter")') 55 | i.fa.fa-twitter 56 | | Connect with Twitter<% } %><% } %> 57 | hr 58 | -------------------------------------------------------------------------------- /app/templates/server/auth(auth)/auth.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var passport = require('passport'); 4 | var config = require('../config/environment'); 5 | var jwt = require('jsonwebtoken'); 6 | var expressJwt = require('express-jwt'); 7 | var compose = require('composable-middleware'); 8 | var validateJwt = expressJwt({ 9 | secret: config.secrets.session 10 | }); 11 | 12 | function User(req){ 13 | if(req.app.get('models')) 14 | return req.app.get('models').User; 15 | else 16 | return req.app.settings.models.User; 17 | } 18 | 19 | /** 20 | * Attaches the user object to the request if authenticated 21 | * Otherwise returns 403 22 | */ 23 | function isAuthenticated() { 24 | return compose() 25 | // Validate jwt 26 | .use(function(req, res, next) { 27 | // allow access_token to be passed through query parameter as well 28 | if (req.query && req.query.hasOwnProperty('access_token')) { 29 | req.headers.authorization = 'Bearer ' + req.query.access_token; 30 | } 31 | validateJwt(req, res, next); 32 | }) 33 | // Attach user to request 34 | .use(function(req, res, next) { 35 | User(req) 36 | .find({ where: { _id: req.user._id } }) 37 | .then(function(user) { 38 | if(!user){ return res.status(401).end(); } 39 | req.user = user; 40 | next(); 41 | }) 42 | .catch(function(err) { 43 | return next(err); 44 | }); 45 | }); 46 | } 47 | 48 | /** 49 | * Checks if the user role meets the minimum requirements of the route 50 | */ 51 | function hasRole(roleRequired) { 52 | if (!roleRequired) { 53 | throw new Error('Required role needs to be set'); 54 | } 55 | 56 | return compose() 57 | .use(isAuthenticated()) 58 | .use(function meetsRequirements(req, res, next) { 59 | if (config.userRoles.indexOf(req.user.role) >= 60 | config.userRoles.indexOf(roleRequired)) { 61 | next(); 62 | } else { 63 | res.status(403).send('Forbidden'); 64 | } 65 | }); 66 | } 67 | 68 | /** 69 | * Returns a jwt token signed by the app secret 70 | */ 71 | function signToken(id, role) { 72 | return jwt.sign({ _id: id, role: role }, config.secrets.session, { 73 | expiresInMinutes: 60 * 5 74 | }); 75 | } 76 | 77 | /** 78 | * Set token cookie directly for oAuth strategies 79 | */ 80 | function setTokenCookie(req, res) { 81 | if (!req.user) { 82 | return res.status(404).send('Something went wrong, please try again.'); 83 | } 84 | var token = signToken(req.user._id, req.user.role); 85 | res.cookie('token', token); 86 | res.redirect('/'); 87 | } 88 | 89 | exports.isAuthenticated = isAuthenticated; 90 | exports.hasRole = hasRole; 91 | exports.signToken = signToken; 92 | exports.setTokenCookie = setTokenCookie; 93 | -------------------------------------------------------------------------------- /app/templates/client/components/modal(uibootstrap)/modal.service(js).js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= scriptAppName %>') 4 | .factory('Modal', function ($rootScope, $modal) { 5 | /** 6 | * Opens a modal 7 | * @param {Object} scope - an object to be merged with modal's scope 8 | * @param {String} modalClass - (optional) class(es) to be applied to the modal 9 | * @return {Object} - the instance $modal.open() returns 10 | */ 11 | function openModal(scope, modalClass) { 12 | var modalScope = $rootScope.$new(); 13 | scope = scope || {}; 14 | modalClass = modalClass || 'modal-default'; 15 | 16 | angular.extend(modalScope, scope); 17 | 18 | return $modal.open({ 19 | templateUrl: 'components/modal/modal.html', 20 | windowClass: modalClass, 21 | scope: modalScope 22 | }); 23 | } 24 | 25 | // Public API here 26 | return { 27 | 28 | /* Confirmation modals */ 29 | confirm: { 30 | 31 | /** 32 | * Create a function to open a delete confirmation modal (ex. ng-click='myModalFn(name, arg1, arg2...)') 33 | * @param {Function} del - callback, ran when delete is confirmed 34 | * @return {Function} - the function to open the modal (ex. myModalFn) 35 | */ 36 | delete: function(del) { 37 | del = del || angular.noop; 38 | 39 | /** 40 | * Open a delete confirmation modal 41 | * @param {String} name - name or info to show on modal 42 | * @param {All} - any additional args are passed staight to del callback 43 | */ 44 | return function() { 45 | var args = Array.prototype.slice.call(arguments), 46 | name = args.shift(), 47 | deleteModal; 48 | 49 | deleteModal = openModal({ 50 | modal: { 51 | dismissable: true, 52 | title: 'Confirm Delete', 53 | html: '

Are you sure you want to delete ' + name + ' ?

', 54 | buttons: [{ 55 | classes: 'btn-danger', 56 | text: 'Delete', 57 | click: function(e) { 58 | deleteModal.close(e); 59 | } 60 | }, { 61 | classes: 'btn-default', 62 | text: 'Cancel', 63 | click: function(e) { 64 | deleteModal.dismiss(e); 65 | } 66 | }] 67 | } 68 | }, 'modal-danger'); 69 | 70 | deleteModal.result.then(function(event) { 71 | del.apply(event, args); 72 | }); 73 | }; 74 | } 75 | } 76 | }; 77 | }); 78 | -------------------------------------------------------------------------------- /app/templates/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '', 8 | 9 | // testing framework to use (jasmine/mocha/qunit/...) 10 | frameworks: ['jasmine'], 11 | 12 | // list of files / patterns to load in the browser 13 | files: [ 14 | 'client/bower_components/jquery/dist/jquery.js', 15 | 'client/bower_components/angular/angular.js', 16 | 'client/bower_components/angular-mocks/angular-mocks.js', 17 | 'client/bower_components/angular-resource/angular-resource.js', 18 | 'client/bower_components/angular-cookies/angular-cookies.js', 19 | 'client/bower_components/angular-sanitize/angular-sanitize.js', 20 | 'client/bower_components/angular-route/angular-route.js',<% if(filters.uibootstrap) { %> 21 | 'client/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',<% } %> 22 | 'client/bower_components/lodash/dist/lodash.compat.js',<% if(filters.socketio) { %> 23 | 'client/bower_components/angular-socket-io/socket.js',<% } %><% if(filters.uirouter) { %> 24 | 'client/bower_components/angular-ui-router/release/angular-ui-router.js',<% } %> 25 | 'client/app/app.js', 26 | 'client/app/app.coffee', 27 | 'client/app/**/*.js', 28 | 'client/app/**/*.coffee', 29 | 'client/components/**/*.js', 30 | 'client/components/**/*.coffee', 31 | 'client/app/**/*.jade', 32 | 'client/components/**/*.jade', 33 | 'client/app/**/*.html', 34 | 'client/components/**/*.html' 35 | ], 36 | 37 | preprocessors: { 38 | '**/*.jade': 'ng-jade2js', 39 | '**/*.html': 'html2js', 40 | '**/*.coffee': 'coffee', 41 | }, 42 | 43 | ngHtml2JsPreprocessor: { 44 | stripPrefix: 'client/' 45 | }, 46 | 47 | ngJade2JsPreprocessor: { 48 | stripPrefix: 'client/' 49 | }, 50 | 51 | // list of files / patterns to exclude 52 | exclude: [], 53 | 54 | // web server port 55 | port: 8080, 56 | 57 | // level of logging 58 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 59 | logLevel: config.LOG_INFO, 60 | 61 | 62 | // enable / disable watching file and executing tests whenever any file changes 63 | autoWatch: false, 64 | 65 | 66 | // Start these browsers, currently available: 67 | // - Chrome 68 | // - ChromeCanary 69 | // - Firefox 70 | // - Opera 71 | // - Safari (only Mac) 72 | // - PhantomJS 73 | // - IE (only Windows) 74 | browsers: ['PhantomJS'], 75 | 76 | 77 | // Continuous Integration mode 78 | // if true, it capture browsers, run tests and exit 79 | singleRun: false 80 | }); 81 | }; 82 | -------------------------------------------------------------------------------- /app/templates/server/config/environment/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var _ = require('lodash'); 5 | 6 | function requiredProcessEnv(name) { 7 | if(!process.env[name]) { 8 | throw new Error('You must set the ' + name + ' environment variable'); 9 | } 10 | return process.env[name]; 11 | } 12 | 13 | // All configurations will extend these options 14 | // ============================================ 15 | var all = { 16 | env: process.env.NODE_ENV, 17 | 18 | // Root path of server 19 | root: path.normalize(__dirname + '/../../..'), 20 | 21 | // Server port 22 | port: process.env.PORT || 9000, 23 | 24 | // Server IP 25 | ip: process.env.IP || 'localhost', 26 | 27 | // Should we populate the DB with sample data? 28 | seedDB: true, 29 | 30 | // Secret for session, you will want to change this and make it an environment variable 31 | secrets: { 32 | session: '<%= _.slugify(_.humanize(appname)) + '-secret' %>' 33 | }, 34 | 35 | // List of user roles 36 | userRoles: ['guest', 'user', 'admin'], 37 | 38 | // MongoDB connection options 39 | mongo: { 40 | options: { 41 | db: { 42 | safe: true 43 | } 44 | } 45 | }, 46 | 47 | sql: { 48 | host: 'localhost', 49 | dialect: <% if(filters.pgsql){ %>'postgres'<% } %><% if(filters.mssql){ %>'mssql'<% } %><% if(filters.mysql){ %>'mysql'<% } %><% if(filters.mariasql){ %>'mariadb' <% } %><% if(filters.sqlite){ %>'sqlite'<% } %>, 50 | protocol:<% if(filters.pgsql){ %>'postgres'<% } %><% if(filters.mssql){ %>'mssql'<% } %><% if(filters.mysql){ %>'mysql'<% } %><% if(filters.mariasql){ %>'mariadb' <% } %><% if(filters.sqlite){ %>'sqlite'<% } %>, 51 | pool: { 52 | max: 5, 53 | min: 0, 54 | idle: 10000 55 | }, 56 | database: '<%= _.slugify(appname) %>', 57 | username: 'postgres', 58 | password: 'root' 59 | }, 60 | <% if(filters.facebookAuth) { %> 61 | facebook: { 62 | clientID: process.env.FACEBOOK_ID || 'id', 63 | clientSecret: process.env.FACEBOOK_SECRET || 'secret', 64 | callbackURL: (process.env.DOMAIN || '') + '/auth/facebook/callback' 65 | }, 66 | <% } %><% if(filters.twitterAuth) { %> 67 | twitter: { 68 | clientID: process.env.TWITTER_ID || 'id', 69 | clientSecret: process.env.TWITTER_SECRET || 'secret', 70 | callbackURL: (process.env.DOMAIN || '') + '/auth/twitter/callback' 71 | }, 72 | <% } %><% if(filters.googleAuth) { %> 73 | google: { 74 | clientID: process.env.GOOGLE_ID || 'id', 75 | clientSecret: process.env.GOOGLE_SECRET || 'secret', 76 | callbackURL: (process.env.DOMAIN || '') + '/auth/google/callback' 77 | }<% } %> 78 | }; 79 | 80 | // Export the config object based on the NODE_ENV 81 | // ============================================== 82 | module.exports = _.merge( 83 | all, 84 | require('./' + process.env.NODE_ENV + '.js') || {}); 85 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 4 | 5 | Additionally for this generator: 6 | 7 | * Please submit PRs to the `canary` branch, it is the main development branch for this generator. 8 | * When submitting an issue, please follow the [guidelines](https://github.com/yeoman/yeoman/blob/master/contributing.md#issue-submission). Especially important is to make sure Yeoman is up-to-date, and providing the command or commands that cause the issue. 9 | * When submitting a PR, make sure that the commit messages match the [AngularJS conventions][commit-message-format] (see below). 10 | * When submitting a bugfix, write a test that exposes the bug and fails before applying your fix. Submit the test alongside the fix. 11 | * When submitting a new feature, add tests that cover the feature. 12 | 13 | ## Git Commit Guidelines 14 | 15 | These rules are adopted from the AngularJS project. 16 | 17 | ### Commit Message Format 18 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special 19 | format that includes a **type**, a **scope** and a **subject**: 20 | 21 | ``` 22 | (): 23 | 24 | 25 | 26 |